Tracking WP PHP Object Injection Attackers in November

Over the past month or so I have been monitoring the activity of a series of attacks against our hosting customers which had one common vector: insecure WordPress plugins which exposed PHP objects to potential injection. Only a very small number of our customers were affected and with every compromised instance we work with our customers and provide every detail we can regarding the attack. In this case we found the vulnerability being exploited was an unpublished (or zero day) exploit in the wild. As we worked to mitigate the vulnerability we kept an open dialog with our affected customers as we worked with the plugin author on a patch or in some cases: disabling the insecure plugin.

About PHP object injection attacks

The attack we saw was not a new type of attack, but an attack method that is a little obscure compared to the more commonly talked about: XSS and/or SQLi. PHP Object Injection is discussed in depth by security groups like OWASP as well as being so severe it warranted a large red warning on php.net warning not to utilize the unserialize() function with untrusted data. Many plugin developers have fallen short of this best practice and utilized this function insecurely from what we have seen when reviewing the official wordpress.org plugin repository en mass.

How it went down

The attacks started late October, and I recall that I spent Halloween day looking into the first few cases.

The attackers actions, likely an automated script, were fairly easy to track. They would scan a site looking for active installs of certain plugins, then make a POST request to ../admin-ajax.php or /index.php. Right around the same time of the POST request being made – a backdoor would have appeared on the site which the attackers would then leverage to take further malicious actions.

Our security systems did not prevent the attacks at first, but PressARMOR was able to detect them and notified our InfoSec team who performed a proper and thorough incident response on each compromised site. Our incident response protocol:

  • notify the customer
  • clean the site
  • identify the source of the compromise
  • communicate finding’s to the customer
  • shore up our own defense to prevent the same attack from being successful in the future
  • flag the site for further scrutiny/follow-up to check our work

In the first few incidents we identified a common target of the attacks was a plugin named: bp-profile-search. We performed a security audit of the plugin’s code identifying a few possible exploit vectors, our InfoSec team along with help from our DevOps team concluded that the most likely culprit was a PHP object injection attack which was being exposed by an AJAX action in the plugin.

Not certain of the exact exploited object but knowing at least that the injection point was there – we reached out to the author of bp-profile-search directly. The author was extremely receptive to the information we had provided them and within a day had re-written the plugin’s logic to utilize JSON structures instead of serialized objects to store and retrieve that data. And like actual magic, not that wierd David Blaine stuff, we immediately saw the vulnerability in bp-profile-search close and no further sites were using it were affected.

This was an unpublished attack vector utilizing PHP Object injections.

A week or so later we identified a new series of attacks now targeting analytics-counter. We followed our incident response protocol and the similar conclusion was made, that the analytics-counter plugin was also vulnerable to PHP Object Injections. This time it was not as easy to work with the plugin author as the plugin had been removed from the plugin repository recently – The removeal had the unfortunate side effect of making patches in the plugin unavailable to anyone and making it harder for us to reach out to the plugin author directly.

Over several days we continued to monitor compromised sites in hopes to enact a virtual patch (ruleset in our firewall) to protect them but ultimately we had to take action by removing the plugin from all Pagely sites which utilized it. Each site owner was notified directly about the concerns and we worked with them to find suitable replacements if requested.

Since the removal of the analytics-counter plugin across our platform: those sites that were using it have not been affected again. A strong corollary that we identified yet another unpublished vulnerability and successfully took action to protect our customer’s sites.

Shortly after we removed the plugin from our network, this plugin re-appeared on the official repository with a patch issued 2-3 weeks prior which appeared to have addressed this vulnerability to some degree.

Takeaways

What we learned from this is that PHP Object Injection attacks are extremely serious. Attackers were able to arbitrarily execute code and/or upload files. If this issue is not mitigated across all vulnerable plugins it may have the potential to reach a RevSlider or TimThumb level of damage.

A simple fix is that plugin and theme developers need to: immediately stop utilizing the unserialize() function on untrusted data structures. This is in line with what both OWASP and php.net recommends.

However – this vulnerability is a bit more complex as it requires more than just an insecure usage of unserialize(), it also requires an insecure object class to have been created – and this class may or may not be in WP Core – we simply have not had enough time to fully investigate that hypothesis.

We briefly weighed the nuclear option of blocking all requests that contain serialized data but did not as the problem is so many plugins currently (insecurely) use it now that it would adversely affect many customers. Our hope is still that plugin authors are educated about this risk and can take the necessary steps now to patch their code before it gets exploited in the wild and becomes a major issue.

Plugin security reporting works, when all parties treat each other respectfully and talk about the subject and solutions at hand. I have rarely had issues helping developers understand and patch vulnerabilities found in their code – when I am able to speak directly with them that is, and we are happy to help in that capacity now, simply reach out to security . at . pagely . com if you would like some assistance. With cooperation and understanding the community grows.

The Proper Channels

During these events we reached out to the team that manages the wordpress.org plugin repository, detailing our experience with affected plugins and the classification of vulnerability. Naming multiple affected plugins and citing one example specifically in code. We were asked for working proof of concept’s for all instances we found – writing these proof of concepts is not a trivial task, let alone writing a few hundred. Due to time constraints we were unable to meet that request but trust the plugin security team will use the information we did provide to the fullest extent.

Conclusion

It was an exciting November, I hope that getting a few of these patches out and working with cooperative plugin authors helped save others from having a similar problem. It is our goal to continue keeping our customer’s sites secure even in the face of unpublished vulnerabilities and if we must, provide the details of any discovered vulnerabilities so sites hosted everywhere also receive security patches to prevent compromises everywhere for the platform which hosts such a huge percentage of the entire internet.

Note: As we mentioned, the two cited plugins above are just a sample of the plugins we identified as vulnerable, we will continue to reach out to the many other plugin authors as time permits and pass our findings back to the wordpress.org plugin team.

2 Comments

  1. Tony Perez
    Tony Perez

    Hey Robert

    Would you be open to sharing more of what you were seeing? We’d love to test against, and create the PoC’s if applicable.

    Tony

    1. Robert Rowley
      Robert Rowley

      I’m always open to sharing. With this category of vulnerability the big unknown is that insecure object, building a PoC wouldn’t be too hard once that insecure object is tracked down (or as a work around, just write a new plugin with an insecure object and viola!)