Persistent Cross-Site Scripting (XSS) Vulnerability in WP-Piwik
As we continue to review old third-party data on hacking attempts to identity more vulnerabilities that hackers have likely already discovered in WordPress plugins we spotted a persistent cross-site scripting (XSS) vulnerability in the plugin WP-Piwik.
Back in January a request was made for the file /wp-content/plugins/wp-piwik/js/wp-piwik.js, for what was may have been a probe for usage of the plugin before exploiting it. Looking over that plugin for any obvious issues we found that as of version 1.0.9 anyone (even if they were not logged in) can change the plugin’s settings and through those settings they could add malicious JavaScript code to the website’s page.
With the plugin enabled an instance of the class WP_Piwik is created whenever a WordPress page is loaded. That class is defined in the file /classes/WP_Piwik.php. The constructor in that class calls a function setup():
20 21 22 23 24 25 | public function __construct() { global $blog_id; self::$blog_id = (isset ( $blog_id ) ? $blog_id : 'n/a'); $this->openLogger (); $this->openSettings (); $this->setup (); |
That in turn will call the function applySettings() if the function isConfigSubmitted() is true:
41 42 43 44 45 46 47 48 | private function setup() { self::$pluginBasename = plugin_basename ( __FILE__ ); if (! $this->isInstalled ()) $this->installPlugin (); elseif ($this->isUpdated ()) $this->updatePlugin (); if ($this->isConfigSubmitted ()) $this->applySettings (); |
The isConfigSubmitted() will return true if the POST input “wp-piwik” exists:
617 618 619 | private function isConfigSubmitted() { return isset ( $_POST ) && isset ( $_POST ['wp-piwik'] ); } |
The applySettings() function in turns call the applyChanges() function:
566 567 | private function applySettings() { self::$settings->applyChanges ( $_POST ['wp-piwik'] ); |
The applyChanges() function (located in the file /classes/WP_Piwik/Settings.php) will update the plugin’s settings without doing any checks to make sure an authorized user is the one trying to update them:
277 278 279 280 281 282 283 284 285 286 | public function applyChanges($in) { $in = $this->checkSettings ( $in ); self::$wpPiwik->log ( 'Apply changed settings:' ); foreach ( self::$defaultSettings ['globalSettings'] as $key => $val ) $this->setGlobalOption ( $key, isset ( $in [$key] ) ? $in [$key] : $val ); foreach ( self::$defaultSettings ['settings'] as $key => $val ) $this->setOption ( $key, isset ( $in [$key] ) ? $in [$key] : $val ); $this->setGlobalOption ( 'last_settings_update', time () ); $this->save (); } |
By changing the track_mode and tracking_code settings arbitrary JavaScript code can be placed on the website’s pages.
We notified the developer on August 15, but have not heard back from and the plugin has not been fixed. We notified the Plugin Directory of the issue as of this being posted and the plugin will likely be removed from that until it is fixed.
The vulnerability is not exploitable when the plugin is deactivated, so disabling it until it is fixed will protect you. If you still need to use it, a workaround is to disable the changing of settings by editing the file /classes/WP_Piwik.php and commenting out the following lines:
47 48 | if ($this->isConfigSubmitted ()) $this->applySettings (); |
Since the vulnerability may already be exploited we are adding it to the data included with companion plugin for the service, so for those that have our plugin installed they will start getting notified if they are using a vulnerable version of the WP-Piwik plugin installed, even if they are not yet signed up the service.
Proof of Concept
The following proof of concept will cause an alert that says “XSS” to be shown on the website’s pages.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]" method="POST"> <input type="hidden" name="wp-piwik[track_mode]" value="manually" /> <input type="hidden" name="wp-piwik[tracking_code]" value='<script>alert("XSS");</script>' /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- 8/15/2016 – Developer Notified
- 8/29/2016 – WordPress.org Plugin Directory notified.
- 9/2/2016 – Version 1.0.11 released, which fixes vulnerability.
The developer’s change log is showing an update to 1.0.10, with the note “Security Fix.”
https://wordpress.org/plugins/wp-piwik/changelog/
In our testing the changes made in that version didn’t fix the issue.