Timthumb Vulnerability Scanner - Version 1.4

Version Description

  • Largely rewrote codebase to clean up code.
  • Added functionality to download latest version of timthumb rather than relying on static version included in plugin.
  • Added functionality to check if there is a newer version of timthumb available.
  • Added scan to find obvious evidence of intrusion using timthumb exploit.
Download this release

Release Info

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

Code changes from version 1.3 to 1.4

cg-tvs-timthumb-latest.txt CHANGED
@@ -20,10 +20,10 @@
20
  a new version of timthumb.
21
 
22
  */
23
- define ('VERSION', '2.8'); // Version of this script
24
- //Load a config file if it exists. Otherwise, use the values below.
25
- if( file_exists('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.
@@ -114,14 +114,14 @@ if(! defined('WEBSHOT_XVFB_RUNNING') ) define ('WEBSHOT_XVFB_RUNNING', false);
114
  // If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
115
  if(! isset($ALLOWED_SITES)){
116
  $ALLOWED_SITES = array (
117
- 'flickr.com',
118
- 'picasa.com',
119
- 'img.youtube.com',
120
- 'upload.wikimedia.org',
121
- 'photobucket.com',
122
- 'imgur.com',
123
- 'imageshack.us',
124
- 'tinypic.com'
125
  );
126
  }
127
  // -------------------------------------------------------------
@@ -186,7 +186,9 @@ class timthumb {
186
  }
187
  }
188
  $this->cacheDirectory = FILE_CACHE_DIRECTORY;
189
- touch($this->cacheDirectory . '/index.html');
 
 
190
  } else {
191
  $this->cacheDirectory = sys_get_temp_dir();
192
  }
@@ -233,7 +235,7 @@ class timthumb {
233
  $this->debug(2, "Fetching only from selected external sites is enabled.");
234
  $allowed = false;
235
  foreach($ALLOWED_SITES as $site){
236
- if (preg_match ('/(?:^|\.)' . $site . '$/i', $this->url['host'])) {
237
  $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
238
  $allowed = true;
239
  }
@@ -348,7 +350,7 @@ class timthumb {
348
  return false;
349
  } else { //Otherwise serve a 304
350
  $this->debug(3, "File has not been modified since last get, so serving a 304.");
351
- header ('HTTP/1.1 304 Not Modified');
352
  $this->debug(1, "Returning 304 not modified");
353
  return true;
354
  }
@@ -407,7 +409,7 @@ class timthumb {
407
  $html .= '<li>' . htmlentities($err) . '</li>';
408
  }
409
  $html .= '</ul>';
410
- header ('HTTP/1.1 400 Bad Request');
411
  echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
412
  echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
413
  echo '<br />TimThumb version : ' . VERSION . '</pre>';
@@ -442,13 +444,17 @@ class timthumb {
442
  //If this is a new timthumb installation we need to create the file
443
  if(! is_file($lastCleanFile)){
444
  $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
445
- touch($lastCleanFile);
 
 
446
  return;
447
  }
448
  if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
449
  $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
450
  // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
451
- touch($lastCleanFile);
 
 
452
  $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
453
  $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
454
  foreach($files as $file){
@@ -812,7 +818,7 @@ class timthumb {
812
  }
813
  protected function getLocalImagePath($src){
814
  $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
815
- $realDocRoot = realpath($this->docRoot); //See issue 224. Using realpath as a windows fix.
816
  if(! $this->docRoot){
817
  $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.");
818
  //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
@@ -827,7 +833,7 @@ class timthumb {
827
  if(file_exists ($this->docRoot . '/' . $src)) {
828
  $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
829
  $real = realpath($this->docRoot . '/' . $src);
830
- if(strpos($real, $realDocRoot) === 0){
831
  return $real;
832
  } else {
833
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
@@ -839,21 +845,30 @@ class timthumb {
839
  if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
840
  $this->debug(3, "Found absolute path: $absolute");
841
  if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
842
- if(strpos($absolute, $realDocRoot) === 0){
843
  return $absolute;
844
  } else {
845
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
846
  //and continue search
847
  }
848
  }
 
849
  $base = $this->docRoot;
850
- foreach (explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME'])) as $sub){
 
 
 
 
 
 
 
 
851
  $base .= $sub . '/';
852
  $this->debug(3, "Trying file as: " . $base . $src);
853
  if(file_exists($base . $src)){
854
  $this->debug(3, "Found file as: " . $base . $src);
855
  $real = realpath($base . $src);
856
- if(strpos($real, $realDocRoot) === 0){
857
  return $real;
858
  } else {
859
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
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.
114
  // If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
115
  if(! isset($ALLOWED_SITES)){
116
  $ALLOWED_SITES = array (
117
+ 'flickr.com',
118
+ 'picasa.com',
119
+ 'img.youtube.com',
120
+ 'upload.wikimedia.org',
121
+ 'photobucket.com',
122
+ 'imgur.com',
123
+ 'imageshack.us',
124
+ 'tinypic.com',
125
  );
126
  }
127
  // -------------------------------------------------------------
186
  }
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();
194
  }
235
  $this->debug(2, "Fetching only from selected external sites is enabled.");
236
  $allowed = false;
237
  foreach($ALLOWED_SITES as $site){
238
+ if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
239
  $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
240
  $allowed = true;
241
  }
350
  return false;
351
  } else { //Otherwise serve a 304
352
  $this->debug(3, "File has not been modified since last get, so serving a 304.");
353
+ header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
354
  $this->debug(1, "Returning 304 not modified");
355
  return true;
356
  }
409
  $html .= '<li>' . htmlentities($err) . '</li>';
410
  }
411
  $html .= '</ul>';
412
+ header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
413
  echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
414
  echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
415
  echo '<br />TimThumb version : ' . VERSION . '</pre>';
444
  //If this is a new timthumb installation we need to create the file
445
  if(! is_file($lastCleanFile)){
446
  $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
447
+ if (!touch($lastCleanFile)) {
448
+ $this->error("Could note create cache clean timestamp file.");
449
+ }
450
  return;
451
  }
452
  if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
453
  $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
454
  // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
455
+ if (!touch($lastCleanFile)) {
456
+ $this->error("Could note create cache clean timestamp file.");
457
+ }
458
  $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
459
  $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
460
  foreach($files as $file){
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
  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
  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.");
852
  //and continue search
853
  }
854
  }
855
+
856
  $base = $this->docRoot;
857
+
858
+ // account for Windows directory structure
859
+ if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
860
+ $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
861
+ } else {
862
+ $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
863
+ }
864
+
865
+ foreach ($sub_directories as $sub){
866
  $base .= $sub . '/';
867
  $this->debug(3, "Trying file as: " . $base . $src);
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.");
readme.txt CHANGED
@@ -11,7 +11,9 @@ Scans your wp-content directory for vulnerable instances of timthumb.php, and op
11
 
12
  The recent Timthumb.php vulnerability (discussed [here](http://markmaunder.com/2011/08/02/technical-details-and-scripts-of-the-wordpress-timthumb-php-hack/)) has left scores of unsuspecting bloggers hacked. It's the perfect combination of not so easy to fix for the technically disinclined, and easy to find and exploit for the malicious - resulting in a disastrous number of compromised sites.
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 fromhackers looking to exploit this particular vulnerability.
 
 
15
 
16
  More info at [CodeGarage](http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin/).
17
 
@@ -26,7 +28,7 @@ Special thanks to [Jacob Gillespie](http://jacobwg.com/) for help with the bulk
26
 
27
  = What does this look for specifically? =
28
 
29
- The scanner checks for instances of timthumb that are older than version 2.0.
30
 
31
  = Where does it look for them? =
32
 
@@ -34,15 +36,23 @@ The entire wp-content directory (even if it's not called wp-content) is scanned,
34
 
35
  = I think I've already been hacked - will this clean it up? =
36
 
37
- No. This plugin exists to make sure your door is locked, not drag the burglers out of your house. If you've already been hacked, all is not lost - there are people out there who will clean up your site for a fee. Look one up instead of just assuming the site is a loss!
 
 
38
 
39
 
40
  == Screenshots ==
41
 
42
- 1. After clicking "Scan!", you'll be presented with a list of safe files found, and unsafe files found. Clicking "Fix" on any unsafe file will replace it with a safe version of timthumb.
43
 
44
  == Changelog ==
45
 
 
 
 
 
 
 
46
  = 1.3 =
47
  * Updated formatting to conform with WP coding standards, added bulk upgrade feature (Thanks to [Jacob Gillespie](http://jacobwg.com/)!).
48
 
11
 
12
  The recent Timthumb.php vulnerability (discussed [here](http://markmaunder.com/2011/08/02/technical-details-and-scripts-of-the-wordpress-timthumb-php-hack/)) has left scores of unsuspecting bloggers hacked. It's the perfect combination of not so easy to fix for the technically disinclined, and easy to find and exploit for the malicious - resulting in a disastrous number of compromised sites.
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
 
28
 
29
  = What does this look for specifically? =
30
 
31
+ The scanner checks for all instances of timthumb it can find. It doesn't just check filename - it looks for code inside the file, ensuring that regardless of what a theme or plugin developer has named the file, it will be caught.
32
 
33
  = Where does it look for them? =
34
 
36
 
37
  = I think I've already been hacked - will this clean it up? =
38
 
39
+ No. This plugin exists to make sure your door is locked, not drag the burglers out of your house. It will run some cursory checks to see if a hacker has likely already hit your site, but has no functionality to clean up the problem.
40
+
41
+ If you've already been hacked, all is not lost - there are people out there who will clean up your site for a fee. Get in touch here: http://codegarage.com/hack-cleanup
42
 
43
 
44
  == Screenshots ==
45
 
46
+ 1. After clicking "Scan!", you'll be presented with a list of all instances of timthumb on your server. Outdated or Unsafe instances are marked as such. Clicking "Upgrade Selected Files" will update selected files to the latest available version of timthumb available on http://code.google.com/p/timthumb/.
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.
53
+ * Added functionality to check if there is a newer version of timthumb available.
54
+ * Added scan to find obvious evidence of intrusion using timthumb exploit.
55
+
56
  = 1.3 =
57
  * Updated formatting to conform with WP coding standards, added bulk upgrade feature (Thanks to [Jacob Gillespie](http://jacobwg.com/)!).
58
 
screenshot-1.png CHANGED
Binary file
timthumb-vulnerability-scanner.php CHANGED
@@ -1,140 +1,17 @@
1
  <?php
2
  /*
3
  Plugin Name: TimThumb Vulnerability Scanner
4
- Plugin URI: http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin/
5
- Description: Find all those pesky timthumb.php scripts with vulnerabilities BEFORE you get hacked! Scans your wp-content directory for vulnerable instances of timthumb.php, and optionally upgrades them.
6
- Author: Peter Butler</a>, <a href="http://jacobwg.com/">Jacob Gillespie
7
- Version: 1.3
8
  Author URI: http://codegarage.com/
9
  */
10
 
 
11
 
12
- // ==============
13
- // = ADMIN MENU =
14
- // ==============
15
-
16
- add_action( 'admin_menu', 'cg_tvs_scanner_menu' );
17
-
18
- function cg_tvs_scanner_menu() {
19
- add_management_page( 'Timthumb Scanner', 'Timthumb Scanner', 'manage_options', 'cg-timthumb-scanner', 'cg_timthumb_scanner_panel' );
20
- }
21
-
22
- function cg_timthumb_scanner_panel() {
23
- if ( ! current_user_can( 'manage_options' ) ) {
24
- wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
25
- }
26
-
27
- if ( isset( $_REQUEST['cg-action'] ) ) {
28
- switch ( $_REQUEST['cg-action'] ) {
29
- case 'scan':
30
- cg_tvs_scan();
31
- break;
32
- case 'fix':
33
- $nonce = $_GET['_wpnonce'];
34
- if ( wp_verify_nonce( $nonce, 'fix_timthumb_file' ) ) {
35
- cg_tvs_fix_file( urldecode( $_GET['file'] ) );
36
- cg_tvs_scan(); // Re-scan site
37
- }
38
- break;
39
- case 'fixall':
40
- $nonce = $_GET['_wpnonce'];
41
- if ( wp_verify_nonce( $nonce, 'fix_all_timthumb_files' ) ) {
42
- $vulnerable_files = get_option( 'cg_tvs_vulnerable_files' );
43
- if ( is_array( $vulnerable_files ) && ! empty( $vulnerable_files ) ) {
44
- foreach ( $vulnerable_files as $file ) {
45
- cg_tvs_fix_file( $file );
46
- }
47
- cg_tvs_scan(); // Re-scan site
48
- }
49
- }
50
- break;
51
- }
52
- }
53
-
54
- $vulnerable_files = get_option( 'cg_tvs_vulnerable_files' );
55
- if( is_array( $vulnerable_files ) && ! empty( $vulnerable_files ) ) {
56
- $vulnerable_list_html = '<ol>';
57
- foreach ( $vulnerable_files as $file ) {
58
- $vulnerable_list_html .= '<li><a href="' . wp_nonce_url( 'tools.php?page=cg-timthumb-scanner&cg-action=fix&file=' . urlencode( $file ), 'fix_timthumb_file') . '" class="button-secondary">Fix</a> <span style="color:red">' . basename( $file ) . '</span> <small>(found at ' . $file . ')</small></li>';
59
- }
60
- $vulnerable_list_html .= '</ol>';
61
- } else {
62
- $vulnerable_list_html = '<span style="color:forestgreen">No Vulnerabilities Found!</span>';
63
- }
64
-
65
- $safe_files = get_option( 'cg_tvs_safe_files' );
66
- if(is_array($safe_files) && !empty($safe_files)) {
67
- $safe_list_html = '<ol>';
68
- foreach($safe_files as $file) {
69
- $safe_list_html .= "<li><span style='color:forestgreen'>" . basename( $file ) . "</span> <small>(found at $file)</small></li>\n";
70
- }
71
- $safe_list_html .= '</ol>';
72
- } else {
73
- $safe_list_html = '<span style="color:forestgreen">No Up to Date Versions Found!</span>';
74
- }
75
- include_once 'cg-tvs-admin-panel.php';
76
- }
77
-
78
- // ==============
79
- // = SCAN FILES =
80
- // ==============
81
-
82
- function cg_tvs_scan() {
83
- require_once 'cg-tvs-filescanner.php';
84
- $scanner = new CG_FileScanner( WP_CONTENT_DIR );
85
- $scanner->generate_inventory();
86
- $scanner->scan_inventory();
87
- update_option( 'cg_tvs_last_checked', date('Y-m-d H:i:s') );
88
- update_option( 'cg_tvs_vulnerable_files', $scanner->VulnerableFiles );
89
- update_option( 'cg_tvs_safe_files', $scanner->SafeFiles );
90
- cg_tsv_show_message('Scan completed.');
91
- }
92
-
93
- // ============
94
- // = FIX FILE =
95
- // ============
96
-
97
- function cg_tvs_fix_file($file, $backup = false ) {
98
- $src_file_path = trailingslashit( dirname( __FILE__ ) ) . 'cg-tvs-timthumb-latest.txt';
99
- if ( FALSE !== $fr = @fopen( $src_file_path, 'r' ) ) {
100
- $latest_src = fread( $fr, filesize( $src_file_path ) );
101
- fclose($fr);
102
- } else {
103
- cg_tsv_show_message( 'CAN\'T READ TIMTHUMB SOURCE FILE', true );
104
- return;
105
- }
106
- if( FALSE !== $fw = @fopen( $file, 'w' ) ) {
107
- if ( fwrite( $fw, $latest_src ) ) {
108
- cg_tsv_show_message( 'File <strong>' . basename( $file ) . '</strong> at <em>' . $file . '</em> successfully upgraded.' );
109
- } else {
110
- cg_tsv_show_message( 'Unknown file write error.', true );
111
- }
112
- } else {
113
- cg_tsv_show_message( 'CAN\'T OPEN VULNERABLE FILE FOR WRITING', true );
114
- return;
115
- }
116
- }
117
-
118
- function cg_tsv_show_message( $message, $error = false )
119
- {
120
- if ($error) {
121
- echo '<div id="message" class="error">';
122
- }
123
- else {
124
- echo '<div id="message" class="updated fade">';
125
- }
126
-
127
- echo "<p><strong>$message</strong></p></div>";
128
- }
129
-
130
- // ================
131
- // = DEACTIVATION =
132
- // ================
133
-
134
- register_deactivation_hook( __FILE__, 'cg_tvs_scan_deactivate' );
135
-
136
- function cg_tvs_scan_deactivate() {
137
- delete_option( 'cg_tvs_last_checked' );
138
- delete_option( 'cg_tvs_vulnerable_files' );
139
- delete_option( 'cg_tvs_safe_files' );
140
- }
1
  <?php
2
  /*
3
  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.4
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->get_fresh_data();
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' ) );