From 50e5362b99bcbc323a94a35281d3bf57b5246f87 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sat, 25 Jul 2015 18:33:30 +0100 Subject: [PATCH] [auto] Plugin: feedwordpress 2015.0514 --- wp-content/plugins/feedwordpress/admin-ui.php | 4 +- .../plugins/feedwordpress/feedwordpress.php | 14 ++-- .../feedwordpresssyndicationpage.class.php | 70 ++++++++++++++++--- wp-content/plugins/feedwordpress/readme.txt | 50 ++++++++++--- .../feedwordpress/syndicatedlink.class.php | 15 +++- .../feedwordpress/syndicatedpost.class.php | 14 +++- 6 files changed, 136 insertions(+), 31 deletions(-) diff --git a/wp-content/plugins/feedwordpress/admin-ui.php b/wp-content/plugins/feedwordpress/admin-ui.php index f0c4ef397..bc3029fa6 100644 --- a/wp-content/plugins/feedwordpress/admin-ui.php +++ b/wp-content/plugins/feedwordpress/admin-ui.php @@ -59,11 +59,13 @@ class FeedWordPressAdminPage { add_action('feedwordpress_check_feed', 'update_feeds_mention'); add_action('feedwordpress_check_feed_complete', 'update_feeds_finish', 10, 3); + $link = $this->link; + print '<div class="updated">'; print "<ul>"; $uri = $this->link->uri(); $displayUrl = $uri; - + // check for effects of an effective-url filter $effectiveUrl = $link->uri(array('fetch' => true)); if ($uri != $effectiveUrl) : $displayUrl .= ' | ' . $effectiveUrl; endif; diff --git a/wp-content/plugins/feedwordpress/feedwordpress.php b/wp-content/plugins/feedwordpress/feedwordpress.php index 98c2feb4a..a92f2f916 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress.php +++ b/wp-content/plugins/feedwordpress/feedwordpress.php @@ -3,7 +3,7 @@ Plugin Name: FeedWordPress Plugin URI: http://feedwordpress.radgeek.com/ Description: simple and flexible Atom/RSS syndication for WordPress -Version: 2014.0805 +Version: 2015.0514 Author: Charles Johnson Author URI: http://radgeek.com/ License: GPL @@ -11,7 +11,7 @@ License: GPL /** * @package FeedWordPress - * @version 2014.0805 + * @version 2015.0514 */ # This uses code derived from: @@ -32,7 +32,7 @@ License: GPL # -- Don't change these unless you know what you're doing... -define ('FEEDWORDPRESS_VERSION', '2014.0805'); +define ('FEEDWORDPRESS_VERSION', '2015.0514'); define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact'); if (!defined('FEEDWORDPRESS_BLEG')) : @@ -1284,7 +1284,7 @@ class FeedWordPress { $sendback .= ( ! empty( $post_type ) ) ? '?post_type=' . $post_type : ''; endif; else : - $sendback = remove_query_arg( array('trashed', 'untrashed', 'deleted', 'zapped', 'unzapped', 'ids'), $sendback ); + $sendback = esc_url( remove_query_arg( array('trashed', 'untrashed', 'deleted', 'zapped', 'unzapped', 'ids'), $sendback ) ); endif; // Make sure we have a post corresponding to this ID. @@ -1324,7 +1324,7 @@ class FeedWordPress { add_post_meta($post_id, '_feedwordpress_zapped_blank_me', 1, /*unique=*/ true); add_post_meta($post_id, '_feedwordpress_zapped_blank_old_status', $old_status, /*unique=*/ true); - wp_redirect( add_query_arg( array('zapped' => 1, 'ids' => $post_id), $sendback ) ); + wp_redirect( esc_url_raw( add_query_arg( array('zapped' => 1, 'ids' => $post_id), $sendback ) ) ); else : $old_status = get_post_meta($post_id, '_feedwordpress_zapped_blank_old_status', /*single=*/ true); @@ -1336,7 +1336,7 @@ class FeedWordPress { delete_post_meta($post_id, '_feedwordpress_zapped_blank_me'); delete_post_meta($post_id, '_feedwordpress_zapped_blank_old_status'); - wp_redirect( add_query_arg( array('unzapped' => 1, 'ids' => $post_id), $sendback ) ); + wp_redirect( esc_url_raw( add_query_arg( array('unzapped' => 1, 'ids' => $post_id), $sendback ) ) ); endif; @@ -1642,7 +1642,7 @@ class FeedWordPress { } /* FeedWordPress::redirect_retired () */ public function row_actions ($actions, $post) { - if (is_syndicated($post->ID)) : + if (is_syndicated($post->ID) && current_user_can('edit_post', $post->ID)) : $link = get_delete_post_link($post->ID, '', true); $eraseLink = MyPHP::url($link, array("fwp_post_delete" => "nuke")); diff --git a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php index f4afb1345..70409e263 100644 --- a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php +++ b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php @@ -70,6 +70,47 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage { return ($this->visibility_toggle() == 'N'); } + /** + * sanitize_ids: Protect id numbers from untrusted sources (POST array etc.) + * from possibility of SQLi attacks. Runs everything through an intval filter + * and then for good measure through esc_sql() + * + * @param array $link_ids An array of one or more putative link IDs + * @return array + */ + public function sanitize_ids_sql ($link_ids) { + $link_ids = array_map( + 'esc_sql', + array_map( + 'intval', + $link_ids + ) + ); + return $link_ids; + } /* FeedWordPressSyndicationPage::sanitize_ids_sql () */ + + /** + * requested_link_ids_sql () + * + * @return string An SQL list literal containing the link IDs, sanitized + * and escaped for direct use in MySQL queries. + * + * @uses sanitize_ids_sql() + */ + public function requested_link_ids_sql () { + // Multiple link IDs passed in link_ids[]=... . . . + $link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array()); + + // Or single in link_id=... + if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif; + + // Filter for safe use in MySQL queries. + $link_ids = $this->sanitize_ids_sql($link_ids); + + // Convert to MySQL list literal. + return "('".implode("', '", $link_ids)."')"; + } /* FeedWordPressSyndicationPage::requested_link_ids_sql () */ + function updates_requested () { global $wpdb; @@ -84,9 +125,14 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage { if ($fwp_update_invoke != 'get') : if (is_array(MyPHP::post('link_ids')) and (MyPHP::post('action')==FWP_UPDATE_CHECKED)) : + // Get single link ID or multiple link IDs from REQUEST parameters + // if available. Sanitize values for MySQL. + $link_list = $this->requested_link_ids_sql(); + + // $link_list has previously been sanitized for html by self::requested_link_ids_sql $targets = $wpdb->get_results(" SELECT * FROM $wpdb->links - WHERE link_id IN (".implode(",",$_POST['link_ids']).") + WHERE link_id IN ${link_list} "); if (is_array($targets)) : foreach ($targets as $target) : @@ -738,10 +784,11 @@ regular donation</a>) using an existing PayPal account or any major credit card. if (MyPHP::post('submit')==FWP_CANCEL_BUTTON) : return true; // Continue without further ado. endif; - - $link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array()); - if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif; - + + // Get single link ID or multiple link IDs from REQUEST parameters + // if available. Sanitize values for MySQL. + $link_list = $this->requested_link_ids_sql(); + if (MyPHP::post('confirm')=='Delete'): if ( is_array(MyPHP::post('link_action')) ) : $actions = MyPHP::post('link_action'); @@ -835,9 +882,10 @@ regular donation</a>) using an existing PayPal account or any major credit card. return true; // Continue on to Syndicated Sites listing else : + // $link_list has previously been sanitized for html by self::requested_link_ids_sql $targets = $wpdb->get_results(" SELECT * FROM $wpdb->links - WHERE link_id IN (".implode(",",$link_ids).") + WHERE link_id IN ${link_list} "); ?> <form action="<?php print $this->form_action(); ?>" method="post"> @@ -907,9 +955,10 @@ regular donation</a>) using an existing PayPal account or any major credit card. // If this is a POST, validate source and user credentials FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_feeds', /*capability=*/ 'manage_links'); - $link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array()); - if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif; - + // Get single link ID or multiple link IDs from REQUEST parameters + // if available. Sanitize values for MySQL. + $link_list = $this->requested_link_ids_sql(); + if (MyPHP::post('confirm')=='Undelete'): if ( is_array(MyPHP::post('link_action')) ) : $actions = MyPHP::post('link_action'); @@ -956,9 +1005,10 @@ regular donation</a>) using an existing PayPal account or any major credit card. return true; // Continue on to Syndicated Sites listing else : + // $link_list has previously been sanitized for html by self::requested_link_ids_sql $targets = $wpdb->get_results(" SELECT * FROM $wpdb->links - WHERE link_id IN (".implode(",",$link_ids).") + WHERE link_id IN ${link_list} "); ?> <form action="<?php print $this->form_action(); ?>" method="post"> diff --git a/wp-content/plugins/feedwordpress/readme.txt b/wp-content/plugins/feedwordpress/readme.txt index 6dc09b3e0..2ea28d8cc 100644 --- a/wp-content/plugins/feedwordpress/readme.txt +++ b/wp-content/plugins/feedwordpress/readme.txt @@ -3,8 +3,8 @@ Contributors: Charles Johnson Donate link: http://feedwordpress.radgeek.com/ Tags: syndication, aggregation, feed, atom, rss Requires at least: 3.0 -Tested up to: 3.9.1 -Stable tag: 2014.0805 +Tested up to: 4.2.2 +Stable tag: 2015.0514 FeedWordPress syndicates content from feeds you choose into your WordPress weblog. @@ -26,12 +26,12 @@ developed, originally, because I needed a more flexible replacement for [Feminist Blogs]: http://feministblogs.org/ FeedWordPress is designed with flexibility, ease of use, and ease of -configuration in mind. You'll need a working installation of WordPress or -WordPress MU (version [3.0] or later), and also FTP or SFTP access to your web -host. The ability to create cron jobs on your web host is helpful but not -required. You *don't* need to tweak any plain-text configuration files and you -*don't* need shell access to your web host to make it work. (Although, I should -point out, web hosts that *don't* offer shell access are *bad web hosts*.) +configuration in mind. You'll need a working installation of WordPress (version +[3.0] or later), and also FTP or SFTP access to your web host. The ability to +create cron jobs on your web host is helpful but not required. You *don't* need +to tweak any plain-text configuration files and you *don't* need shell access +to your web host to make it work. (Although, I should point out, web hosts that +*don't* offer shell access are *bad web hosts*.) [WordPress]: http://wordpress.org/ [WordPress MU]: http://mu.wordpress.org/ @@ -94,8 +94,40 @@ outs, see the documentation at the [FeedWordPress project homepage][]. == Changelog == -= 2014.0805 = += 2015.0514 = + +* IMPORTANT SECURITY UPDATE: This version includes two important fixes for + potential security vulnerabilities reported to me through support channels. + + The first is a common problem across several plugins due to an ambiguity in + the WordPress documentation and a change in the behavior of WordPress's + built-in add_query_arg() and remove_query_arg() functions + which could, under certain low-probability conditions, allow for potential + XSS attack vectors. This fixes issue # 39 + reported at <https://github.com/radgeek/feedwordpress/issues/39> + Thanks to github.com/quassy + + The second is a security vulnerability fixes a security vulnerability that + was reported to me privately (thanks to Adrián M. F.) which, under other + low-probability conditions, could allow for SQL insertion attacks by + a malicious user with access to login credentials, which would compromise + data security. + + It is *IMPORTANT* and worth your while to upgrade FeedWordPress as soon as + possible in order to eliminate these vulnerabilities. If you have any + questions or if there is something blocking you from making the upgrade + which you need my help with, don't hesitate to get in touch. + +* ADMIN UI BUGFIX: "Update Now" button in feeds setting pages should now work + once again instead of causing a PHP fatal error. See + <https://github.com/radgeek/feedwordpress/issues/46> + +* SEVERAL OTHER SMALL BUG FIXES. See <https://github.com/radgeek/feedwordpress/issues/32> + <https://github.com/radgeek/feedwordpress/issues/30> + <https://github.com/radgeek/feedwordpress/issues/29> + etc. += 2014.0805 = * FILTERS AND ADD-ONS: A number of new hooks for filters and add-ons to further customize the behavior of FWP have been added. diff --git a/wp-content/plugins/feedwordpress/syndicatedlink.class.php b/wp-content/plugins/feedwordpress/syndicatedlink.class.php index b34de0c4b..f1d35a9ec 100644 --- a/wp-content/plugins/feedwordpress/syndicatedlink.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedlink.class.php @@ -130,9 +130,9 @@ class SyndicatedLink { $url = $this->uri(array('add_params' => true, 'fetch' => true)); FeedWordPress::diagnostic('updated_feeds', 'Polling feed ['.$url.']'); - + $this->fetch(); - + $new_count = NULL; $resume = ('yes'==$this->setting('update/unfinished')); @@ -178,6 +178,7 @@ class SyndicatedLink { $this->save_settings(/*reload=*/ true); elseif (is_object($this->simplepie)) : + // Success; clear out error setting, if any. $this->update_setting('update/error', NULL); @@ -285,7 +286,9 @@ class SyndicatedLink { break; endif; endif; + unset($post); + endforeach; endif; @@ -720,8 +723,13 @@ class SyndicatedLink { 'fetch' => false, )); + // Initialize $qp (= array for added query parameters, if any) + $qp = array(); + $link_rss = (is_object($this->link) ? $this->link->link_rss : NULL); - + + // $link_rss stores the URI for the subscription as stored in the feed's record. + // $uri stores the effective URI of the request including any/all added query parameters $uri = $link_rss; if (!is_null($uri) and strlen($uri) > 0 and $params['add_params']) : $qp = maybe_unserialize($this->setting('query parameters', array())); @@ -729,6 +737,7 @@ class SyndicatedLink { // For high-tech HTTP feed request kung fu $qp = apply_filters('syndicated_feed_parameters', $qp, $uri, $this); + // $qp is an array of key-value pairs stored as arrays of format [$key, $value] $q = array(); if (is_array($qp) and count($qp) > 0) : foreach ($qp as $pair) : diff --git a/wp-content/plugins/feedwordpress/syndicatedpost.class.php b/wp-content/plugins/feedwordpress/syndicatedpost.class.php index e713b76fb..f8fba139c 100644 --- a/wp-content/plugins/feedwordpress/syndicatedpost.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedpost.class.php @@ -117,6 +117,7 @@ class SyndicatedPost { if (is_null($this->item)) : $this->post = NULL; else : + # Note that nothing is run through esc_sql() here. # That's deliberate. The escaping is done at the point # of insertion, not here, to avoid double-escaping and @@ -127,6 +128,7 @@ class SyndicatedPost { $this->entry->get_title(), $this ); + $this->named['author'] = apply_filters( 'syndicated_item_author', $this->author(), $this @@ -134,7 +136,7 @@ class SyndicatedPost { // This just gives us an alphanumeric name for the author. // We look up (or create) the numeric ID for the author // in SyndicatedPost::add(). - + $this->post['post_content'] = apply_filters( 'syndicated_item_content', $this->content(), $this @@ -348,6 +350,7 @@ class SyndicatedPost { $this->post['post_type'] = apply_filters('syndicated_post_type', $this->link->setting('syndicated post type', 'syndicated_post_type', 'post'), $this); endif; + } /* SyndicatedPost::SyndicatedPost() */ ##################################### @@ -589,6 +592,7 @@ class SyndicatedPost { } /* SyndicatedPost::title () */ function content ($params = array()) { + $params = wp_parse_args($params, array( "full only" => false, )); @@ -635,6 +639,7 @@ class SyndicatedPost { endif; endif; + return $content; } /* SyndicatedPost::content() */ @@ -1213,6 +1218,7 @@ class SyndicatedPost { function resolve_single_relative_uri ($refs) { $tag = FeedWordPressHTML::attributeMatch($refs); $url = SimplePie_Misc::absolutize_url($tag['value'], $this->_base); + return $tag['prefix'] . $url . $tag['suffix']; } /* function SyndicatedPost::resolve_single_relative_uri() */ @@ -1233,11 +1239,17 @@ class SyndicatedPost { foreach ($obj->uri_attrs as $pair) : list($tag, $attr) = $pair; $pattern = FeedWordPressHTML::attributeRegex($tag, $attr); + + // FIXME: Encountered issue while testing an extremely long (= 88827 characters) item + // Relying on preg_replace_callback() here can cause a PHP seg fault on my development + // server. preg_match_all() causes a similar problem. Apparently this is a PCRE issue + // Cf. discussion of similar issue <https://bugs.php.net/bug.php?id=65009> $content = preg_replace_callback ( $pattern, array($obj, 'resolve_single_relative_uri'), $content ); + endforeach; endif; -- GitLab