Headline
CVE-2021-42364: stetic.php in stetic/trunk – WordPress Plugin Repository
The Stetic WordPress plugin is vulnerable to Cross-Site Request Forgery due to missing nonce validation via the stats_page function found in the ~/stetic.php file, which made it possible for attackers to inject arbitrary web scripts in versions up to, and including 1.0.6.
1<?php2/*3Plugin Name: Stetic4Plugin URI: https://www.stetic.com/5Description: Adds real-time Web Analytics from Stetic with event tracking of all important actions to Wordpress. It comes with a dashboard to show you the important reports and numbers.6Author: Stetic7Version: 1.0.68Author URI: https://www.stetic.com/9*/101112if(!class_exists(‘Stetic’))13{14 class Stetic15 {16 17 static private $classobj = null;18 static private $tab = null;19 20 /**21 * construct22 *23 * @uses24 * @access public25 * @since 0.0.126 * @return void27 */28 public function __construct()29 {30 if(is_admin())31 {32 add_action( 'admin_menu’, array( $this, ‘add_page_to_navi’ ) );33 34 if ( empty($GLOBALS[‘pagenow’]) or ( !empty($GLOBALS[‘pagenow’]) && $GLOBALS[‘pagenow’] == ‘index.php’ ) && current_user_can(‘edit_dashboard’) )35 {36 add_action(37 'wp_dashboard_setup’,38 array(39 __CLASS__,40 'add_dashboard_stats’41 )42 );43 }44 }45 }46 47 48 /**49 * points the class50 *51 * @access public52 * @since 0.0.153 * @return object54 */55 public static function get_object() {5657 if ( NULL === self :: $classobj )58 self :: $classobj = new self;5960 return self :: $classobj;61 }62 63 /**64 * Installation hook, will be called on plugin-installation65 *66 */67 public static function install()68 {69 global $wpdb;70 //71 }7273 /**74 * Installation hook, will be called on plugin-uninstall75 *76 */77 public static function uninstall()78 {79 global $wpdb;80 //81 }8283 /**84 * Ads navigation item85 *86 */87 public function add_page_to_navi()88 {89 global $wpdb;90 if ( function_exists(‘add_options_page’) && current_user_can(‘edit_dashboard’) )91 {92 add_options_page('stetic’, 'Stetic’, 'manage_options’, 'stetic/stetic.php&tab=settings’, array('Stetic’, ‘config_page’));93 }94 95 if ( function_exists(‘add_menu_page’) && current_user_can(‘edit_dashboard’) )96 {97 add_menu_page('stetic’, 'Stetic’, 'read’, __FILE__, array( 'Stetic’, ‘stats_page’ ), plugins_url(‘stetic/img/icon.png’));98 }99 100 101 }102103 public static function add_config_page_to_plugins($links, $file)104 {105 if($file == plugin_basename(__FILE__))106 {107 $settings_link = ‘<a href="options-general.php?page=stetic/stetic.php&tab=settings">’ . __(‘Settings’) . '</a>’;108 array_push( $links, $settings_link );109 }110 return $links;111 }112 113 public static function the_tabs()114 {115 ?>116 <h2 class="nav-tab-wrapper">117 <a class="nav-tab<?php echo (!$_GET[‘tab’] || $_GET[‘tab’] == “stats”) ? " nav-tab-active" : “"; ?>” href="admin.php?page=stetic/stetic.php&tab=stats">Stats</a>118 <a class="nav-tab<?php echo ($_GET[‘tab’] == “settings”) ? " nav-tab-active" : “"; ?>” href="options-general.php?page=stetic/stetic.php&tab=settings"><?php echo __(‘Settings’); ?></a>119 </h2>120 <?php121 }122 123 public static function config_page()124 {125 self::$tab = 'settings’;126 self::stats_page();127 }128 129 public static function stats_page()130 {131 if( ! current_user_can(‘edit_dashboard’) )132 {133 return;134 }135 136 if(isset($_POST[‘submit’]))137 {138 $options[‘stetic_token’] = $_POST[‘stetic_token’];139 $options[‘stetic_api_key’] = $_POST[‘stetic_api_key’];140 $options[‘stetic_show_counter’] = $_POST[‘stetic_show_counter’];141 $options[‘stetic_disable_tracking’] = $_POST[‘stetic_disable_tracking’];142 update_option('stetic’, $options);143 }144 145 $options = get_option(‘stetic’);146 147 if($_GET[‘tab’] == ‘settings’ || self::$tab == ‘settings’ || !$options[‘stetic_api_key’])148 {149 ?>150 <div class="wrap">151 <h2>Stetic Configuration</h2>152 <?php self::the_tabs(); ?>153 <form action="" method="post" id="stetic-conf">154 <table class="form-table">155 <tr>156 <td colspan="2">157 <label for="stetic_project_id">Stetic Project Token:</label><br/>158 <input size="50" type="text" id="stetic_token" name="stetic_token" <?php echo 'value="’.$options[‘stetic_token’].’" '; ?>/><br/>159 <small>Please enter your Stetic project token from your <a href="https://www.stetic.com/conf/project-settings/" target="_blank">project settings page</a>.</small>160 </td>161 </tr>162 <tr>163 <td colspan="2">164 <label for="stetic_api_key">Stetic API-Key:</label><br/>165 <input size="50" type="text" id="stetic_api_key" name="stetic_api_key" <?php echo 'value="’.$options[‘stetic_api_key’].’" '; ?>/><br/>166 <small>Please enter your Stetic API-Key from your <a href="https://www.stetic.com/conf/project-settings/" target="_blank">project settings page</a>.</small>167 </td>168 </tr>169 <tr>170 <td colspan="2">171 <label for="stetic_hide_counter">Counter Visibility:</label><br/>172 <input size="50" type="checkbox" id="stetic_show_counter" name="stetic_show_counter" value="1" <?php echo ($options[‘stetic_show_counter’] == “1”) ? ‘checked="checked"’ : “"; ?>/> Show Counter<br/>173 <small>Please select this option if you want to display a counter and have chosen a counter graphic in your project settings.</small>174 </td>175 </tr>176 <tr>177 <td colspan="2">178 <label for="stetic_disable_tracking">Tracking Code:</label><br/>179 <input type="checkbox” id="stetic_disable_tracking" name="stetic_disable_tracking" value="1" <?php echo ($options[‘stetic_disable_tracking’] == “1”) ? ‘checked="checked"’ : “"; ?>/> Disable Tracking<br/>180 <small>Please only choose this option if you allready have the tracking code installed manually.</small>181 </td>182 </tr>183 </table>184 <br/>185 <span class="submit” style="border: 0;"><input type="submit" name="submit" value="Save Settings" /></span>186 </form>187 <br/><br/>188 </div>189 <?php190 }191 else192 {193 /* Get plugin info */194 $plugin_info = get_plugin_data(__FILE__);195196 wp_register_script(197 'google_jsapi’,198 'https://www.google.com/jsapi’,199 false200 );201 wp_enqueue_script(‘google_jsapi’);202 203 wp_register_script(204 'stetic’,205 plugins_url('js/stetic.min.js’, __FILE__),206 array(‘jquery’),207 $plugin_info[‘Version’]208 );209 wp_enqueue_script(‘stetic’);210 211 wp_enqueue_style('stetic-css’,212 plugins_url('css/stetic.css’, __FILE__),213 false,214 $plugin_info[‘Version’],215 false);216 ?>217 <div class="wrap">218 <h2>Stetic</h2>219 <?php self::the_tabs(); ?>220 <div id="contentstetic">221 <h3><?php _e(‘Day Performance’); ?></h3>222 <div id="chart_visitor_div" style="height: 180px; width: 100%;"></div>223 <br>224 225 <table class="widefat" id="fs_overview_stats">226 <thead>227 <tr>228 </tr>229 </thead>230 <tbody>231 </tbody>232 </table>233 234 <br>235 <h3><?php _e(‘Performance last 31 days’); ?></h3>236 <div id="chart_visitor_div_last31" style="height: 180px; width: 100%;"></div>237 238 <br>239 240 <div id="fs-box-row">241 </div>242243 <h3><?php _e(‘Performance this year’); ?></h3>244 <div id="chart_visitor_div_year" style="height: 180px; width: 100%;"></div>245246 <br>247 248 <div>249 <table class="widefat" id="fs-visitor-log">250 <thead><tr><th colspan="3"><?php _e(‘Last 25 Visitors’); ?></th></tr></thead>251 <tbody></tbody>252 </table>253 </div>254 </div>255 </div>256 <script type="text/javascript">257 jQuery(document).ready(function() { 258 fs = new fourStats('<?php echo $options[‘stetic_project_id’]; ?>’, '<?php echo $options[‘stetic_token’]; ?>’, '<?php echo $options[‘stetic_api_key’]; ?>’, '’, ‘<?php echo date(“D, d M Y H:i:s”); ?>’);259 fs.statsPage();260 }); 261 </script>262 <?php263 }264 }265 266 /**267 * Initialisierung des Dashboard-Chart268 *269 * @since 2.0270 * @change 2.0271 */272 public static function add_dashboard_stats()273 {274 if ( !current_user_can(‘edit_dashboard’) )275 {276 return;277 }278279 /* Widget hinzufügen */280 wp_add_dashboard_widget(281 'fs_widget’,282 'Stetic’,283 array(284 __CLASS__,285 'show_dashboard_stats’286 )287 );288289 /* Get plugin info */290 $plugin_info = get_plugin_data(__FILE__);291292 wp_register_script(293 'google_jsapi’,294 'https://www.google.com/jsapi’,295 false296 );297 wp_enqueue_script(‘google_jsapi’);298 299 wp_register_script(300 'stetic’,301 plugins_url('js/stetic.min.js’, __FILE__),302 array(‘jquery’),303 $plugin_info[‘Version’]304 );305 wp_enqueue_script(‘stetic’);306 307 wp_enqueue_style('stetic-css’,308 plugins_url('css/dashboard.css’, __FILE__),309 false,310 $plugin_info[‘Version’],311 false);312 313 }314 315316 /**317 * Ausgabe des Dashboard-Stats318 *319 * @since 2.0320 * @change 2.0321 */322 public static function show_dashboard_stats()323 {324 if ( !current_user_can(‘edit_dashboard’) )325 {326 return;327 }328 $options = get_option(‘stetic’);329 ?>330 <h3><?php _e(‘Day Performance’); ?></h3>331 <div id="chart_visitor_div" style="height: 120px; width: 100%;"></div>332 <br>333 <div id="fs_dashboard_stats">334 </div>335 <p class="textright">336 <a class="button" href="index.php?page=stetic/stetic.php">View All</a>337 </p>338 <script type="text/javascript">339 jQuery(document).ready(function() { 340 fs = new fourStats('<?php echo $options[‘stetic_project_id’]; ?>’, '<?php echo $options[‘stetic_token’]; ?>’, '<?php echo $options[‘stetic_api_key’]; ?>’, ‘’, ‘<?php echo date(“D, d M Y H:i:s”); ?>’);341 fs.dashBoard();342 }); 343 </script>344 <?php345 }346 347 public static function tracking_code_header()348 {349 $options = get_option(‘stetic’);350 if( ( ( isset($options[‘stetic_project_id’]) && $options[‘stetic_project_id’] ) || ( isset($options[‘stetic_token’]) && $options[‘stetic_token’] ) ) && $options[‘stetic_disable_tracking’] != 1 )351 {352 $id_string = ( isset($options[‘stetic_project_id’]) && $options[‘stetic_project_id’] ) ? “siteId=’{$options[‘stetic_project_id’]}’” : “token=’{$options[‘stetic_token’]}’";353 354 if( !isset($options[‘stetic_show_counter’]) || $options[‘stetic_show_counter’] != ‘1’ )355 {356 ?><script type="text/javascript">357var _fss=_fss||{}; _fss.<?php echo $id_string; ?>;358(function(){var e="stetic",a=window,c=[“track","identify","config","set","unset","register","unregister","increment","alias”],b=function(){var d=0,f=this;for(f._fs=[],d=0;c.length>d;d++){(function(j){f[j]=function(){return f._fs.push([j].concat(Array.prototype.slice.call(arguments,0))),f}})(c[d])}};a[e]=a[e]||new b;a.fourstats=a.fourstats||new b;var i=document;var h=i.createElement(“script”);h.type="text/javascript";h.async=true;h.src="//stetic.com/t.js";var g=i.getElementsByTagName(“script”)[0];g.parentNode.insertBefore(h,g)})();359</script><?php360 }361 }362 }363364 public static function tracking_code_footer()365 {366 $options = get_option(‘stetic’);367 368 if( ( ( isset($options[‘stetic_project_id’]) && $options[‘stetic_project_id’] ) 369 || ( isset($options[‘stetic_token’]) && $options[‘stetic_token’] ) ) 370 && $options[‘stetic_disable_tracking’] != 1 )371 {372 $id = ( isset($options[‘stetic_project_id’]) && $options[‘stetic_project_id’] ) ? $options[‘stetic_project_id’] : $options[‘stetic_token’];373 374 if( isset($options[‘stetic_show_counter’]) && $options[‘stetic_show_counter’] == ‘1’ )375 {376 ?><script type="text/javascript">document.write(unescape(‘%3Cscr’ + ‘ipt src="’+’http’+(document.location.protocol==’https:’?’s’:’’)+’://stetic.com/de/counter?id=<?php echo $id; ?>” type="text/javascript"%3E%3C/script%3E’));</script>377<noscript><div><img src="http://stetic.com/de/stats?id=<?php echo $id; ?>" style="border: none;" alt="Stetic" /></div></noscript><?php378 }379 }380 }381 }382}383384if(is_admin()) {385 register_activation_hook( __FILE__, array('Stetic’, ‘install’));386 register_deactivation_hook( __FILE__, array('Stetic’, ‘uninstall’));387 add_action( 'plugins_loaded’, array('Stetic’, ‘get_object’) );388 add_filter( 'plugin_action_links’, array( 'Stetic’, ‘add_config_page_to_plugins’), 11, 2 );389} else {390 add_action('wp_head’, array('Stetic’, ‘tracking_code_header’));391 add_action('wp_footer’, array('Stetic’, ‘tracking_code_footer’));392}