We recently discovered an easily exploitable, vertical privilege escalation vulnerability in every popular, off-the-shelf CMS that we tested.
The lesson: CMSes either need stronger security around user permission updates, or to backtrack away from the convenience afforded by allowing raw HTML editing and publication from non-admin users.
What is a privilege escalation attack?
A privilege escalation attack is the process of exploiting a bug, insecurity, or poor configuration to increase your level of access within a system. Through such an attack, a user who already has a limited degree of access to a CMS can assign themselves the unrestricted access.
Which CMSes are affected?
Just about every CMS that provides unfiltered HTML editing capabilities to non-admin users is vulnerable to XSS-based vertical privilege escalation attacks, even when CSRF protection is in place. We personally validated the attack against Craft, WordPress, and Drupal*.
The vulnerability was responsibly disclosed with exploit samples to each security team in April 2016. The Craft security team immediately responded by releasing a fix for the exploit as a critical update, and is no longer vulnerable in recent versions.
*Note that in its default configuration, Drupal is not vulnerable to this attack as the administrator user role is the only role able to author unfiltered HTML, however nearly all organizations we’ve seen use a more complex system of user roles and permissions which increase their susceptibility to this attack.
What is the outcome of the attack?
Non-admin CMS users can update their user account’s role to admin status. This typically provides the attacker with a large number of new exploitable vectors. (e.g. download a database backup to crack contained hashed passwords, deploy a broader XSS attack within a CMS theme template file, deface the public website, etc.)
Technical Attack Summary
The attack is a straightforward XSS exploit.
I: The Exploit Script
It is a common misconception that CSRF-protection mechanisms are useful against these sorts of XSS attacks, however CSRF-protection merely adds one additional, trivial step to the attack process.
II: Exploit Deployment
With the exploit script in hand, an attacker can drop the script anywhere in the CMS where unescaped, unfiltered HTML is displayed. (This is almost everywhere in most popular CMS configurations.)
Some doubt that attackers would be so bold as to place obviously malicious code directly into their own blog posts or page updates. Keen attackers, however, will obfuscate the intention of the exploit script before deployment to avoid detection, perhaps through minification and encoding.
<script> eval(window.atob('RGlkIHlvdSByZWFsbHkgdGhpbmsgSSdkIGp1c3QgZ2l2ZSB5b3UgYW4gYXR0YWNrIHNjcmlwdD8gVGhlIGxhdyBpcyBub3QgcGVyZmVjdGx5IGNsZWFyIG9uIHRoaXMgbWF0dGVyLCBidXQgaXQgY2FuIGJlIGFyZ3VlZCB0aGF0IHB1Ymxpc2hpbmcgYXR0YWNrcyBpcyBhIGNyaW1pbmFsIGFjdGl2aXR5LiBJJ20gbm90IGEgZmFuIG9mIGdvdmVybm1lbnQgZmluZXMgb3IgamFpbCwgc28gSSdtIHB1Ymxpc2hpbmcgdGhpcyBzaWxseSBtZXNzYWdlIGluc3RlYWQuIEFuZCBpZiB5b3UgYWN0dWFsbHkgdG9vayB0aGUgdGltZSB0byBkZWNvZGUgdGhpcywgd2UnZCBwcm9iYWJseSBlbmpveSB3b3JraW5nIHdpdGggeW91LiBIaXQgdXMgdXAgYXQgam9ic0B2aWdldC5jb20gYW5kIHRlbGwgdGhlbSBMYXdzb24gc2VudCB5b3UuIENoZWVycy4=')); </script>
Still too obvious? How about:
<script> // Omniture Tracking Snippet var omTrack = eval(window.atob('RGlkIHlvdSByZWFsbHkgdGhpbmsgSSdkIGp1c3QgZ2l2ZSB5b3UgYW4gYXR0YWNrIHNjcmlwdD8gVGhlIGxhdyBpcyBub3QgcGVyZmVjdGx5IGNsZWFyIG9uIHRoaXMgbWF0dGVyLCBidXQgaXQgY2FuIGJlIGFyZ3VlZCB0aGF0IHB1Ymxpc2hpbmcgYXR0YWNrcyBpcyBhIGNyaW1pbmFsIGFjdGl2aXR5LiBJJ20gbm90IGEgZmFuIG9mIGdvdmVybm1lbnQgZmluZXMgb3IgamFpbCwgc28gSSdtIHB1Ymxpc2hpbmcgdGhpcyBzaWxseSBtZXNzYWdlIGluc3RlYWQuIEFuZCBpZiB5b3UgYWN0dWFsbHkgdG9vayB0aGUgdGltZSB0byBkZWNvZGUgdGhpcywgd2UnZCBwcm9iYWJseSBlbmpveSB3b3JraW5nIHdpdGggeW91LiBIaXQgdXMgdXAgYXQgam9ic0B2aWdldC5jb20gYW5kIHRlbGwgdGhlbSBMYXdzb24gc2VudCB5b3UuIENoZWVycy4=')); omTrack.linkTrackVars="eVar45,events"; omTrack.linkTrackEvents="event23"; omTrack.eVar45="MaturingEquityLine"; </script> <!-- That's right. Nobody at your company actually knows how Omniture works. -->
III: Phishing Around
After the exploit has been deployed, the attacker now needs only to guide an admin to the deployed exploit. Unfortunately, common CMS workflow practices make this insanely easy.
Once the target hits the deployment, the script executes in the context of the admin’s session. The CMS trusts the target’s session, so it fulfills the permission escalation request without hesitation.
The attacker is now a system admin and the target is none the wiser.
Defending Against the Attack
Being attacked sucks. Fortunately there are steps each of us can take to protect ourselves and our teammates from this sort of attack.
- Use strong and unique passwords. CMS privilege escalation can often provide access to database backups which contain encrypted user passwords. It is much more difficult for an attacker to decrypt your password if you have a long password (that isn’t just an obvious word with some numbers tagged on to the end). If your password is decrypted, and you reuse the same password elsewhere, this limited scope attack can become considerably more damaging.
- Be skeptical. Don’t even click on links sent to you from people you don’t trust (especially not links found in sketchy emails). Contact your security team if anything ever feels weird or fishy.
For Site Developers/Administrators
- Keep your CMS updated to the latest version. Releases often contain security fixes that may patch vulnerabilities such as the one described above. These releases can often actually show attackers where vulnerabilities existed in older versions, so your site is extra vulnerable if you choose not to update.
- Consider applying a content security policy to your site that prohibits execution of untrusted scripts to remove the XSS vector that CMS WYSIWYG editors typically provide. (Unfortunately these types of CSPs are extremely onerous. Get ready to do some serious lifting.)
- Don’t provide CMS access (particularly access to post raw HTML) to anybody that you would not trust as a CMS admin. Have others draft content in a Google Doc, and have a trusted user copy it over.
- Stay logged out of sites unless you need to be logged in to complete your current task. (Yep, actually use that log out button.)
For CMS Developers/Maintainers
- Require reauthentication for all requests attempting to modify user permissions. (This is the approach with which Craft has mitigated this exploit.)
- Limit the scope of CMS actions that can be performed from a web portal (e.g. not providing an online file editor… looking at you WordPress).
- Store database backups securely, and keep them inaccessible from the CMS’s web interface.