Archive for May, 2007

Writing Secure WordPress Plugins

Title: Writing Secure WordPress Plugins (part 1)
Author: David Kierznowski
Site: Operation n
Date: 17 May 2007

Table of Contents

  1. Introduction
  2. attribute_escape
  3. wp_nonce
  4. Summary
  5. References

Introduction

WordPress has become one of the most popular blogging packages on the Internet; this is largely due to its ease of use and its object oriented design which allows the user to easily extend its capabilities in the form of WordPress Plugins.

Unfortunately, "ease of use", and "security" are to often like lemon and milk. This article is a desparate attempt to try and educate WordPress Plugin developers to some of the common security problems that can occur. The reality is, that this article is a bit to late, and unfortunately countless plugins are vulnerable to the attacks discussed here.

What does this mean? Well, it means that an attacker could potentially gain access to your WordPress Admin Panel, or take control of areas of your blogs such as your Google Adsense ads - maybe the attacker wants a little extra pocket money.

On the positive side, WordPress itself, does support a number of built in security functions to help combat these issues.

Rather then tackling all the problems in one go, this paper introduces 2 common pitfalls developers are making when writing WordPress plugins. After going through this article I hope developers of plugins (especially popular ones) will begin immediately working to resolve these issues. When this occurs, we’ll look at part 2 of this article.

I am hesitent to release this information as I know just how many plugins these vulnerabilities affect. For this reason, I will try not discuss to much on the exploitation side (although both are fairly trivial to exploit), but rather give guidelines to follow.

attribute_escape

Right lets get into it… the functions we will be discussing are "attribute_escape" and "wp_nonce_field".

Firstly, the attribute_escape function is defined as follows:

applied to post text and other content by the attribute_escape function, which is called in many places in WordPress to change certain characters into HTML attributes before sending to the browser.

You should use this function everytime you intend to echo back data to the user. This generally means all strings from $_GET and $_POST. Lets have an example to illustrate this (this vulnerable code is actually taken from a plugin):

if( isset($_POST['name']) && $_POST['name'] != ''
           && isset($_POST['code']) && $_POST['code'] != '' ){
            $desc = $_POST['comment'];
            ....

Now can you spot any problems in the above snippet of code? The problem here, is that the plugin is accepting any value that the user chooses as part of the POST variable named desc. This is not good, as any input including HTML entities will be echoed back to the users browser - Note, this also applies to $_GET as well (it even extends to other global variables supported by PHP, but that is beyond the scope of this paper). So lets secure this using the WordPress attribute_escape function:

if( isset($_POST['name']) && $_POST['name'] != ''
           && isset($_POST['code']) && $_POST['code'] != '' ){
            $desc = attribute_escape($_POST['comment']);
            ....

Notice how simple it is to implement this function.

Lets have a $_GET example (also taken from a plugin):

if ( isset($_GET['mode']) ) {
      $mode = $_GET['mode'];
      ...

Again, we see that we fail to escape our request from the user with add_attribute. So lets add it:

if ( isset($_GET['mode']) ) {
      $mode = attribute_escape($_GET['mode']);
      ...

Applying attribute_escape will greatly increase the security of your plugin. Remember the basic rule, if your plugin echoes back data to the user, ensure that attribute_escape is being used before this occurs.

wp_nonce

Our next security feature to our script is to add a random nonce value when using forms. The WordPres definition is as follows:


explain_nonce_(verb)-(noun)
allows a filter function to define text to be used to explain a nonce that is otherwise not explained by the WordPress core code. You will need to define specific verb/noun filters to use this. For instance, if your plugin defines a nonce for updating a tag, you would define a filter for “explain_nonce_update-tag”. Filter function arguments: text to display (defaults to a generic “Are you sure you want to do this?” message) and extra information from the end of the action URL. In the example here, your function might simply return the string “Are you sure you want to update this tag?”.

There is typically three parts to this:

1st, we check to see if this functionality exists and set it at the top of our plugin:

if ( !function_exists('wp_nonce_field') ) {
        function myplugin_nonce_field($action = -1) { return; }
        $myplugin_nonce = -1;
} else {
        function myplugin_nonce_field($action = -1) { return wp_nonce_field($action); }
        $myplugin_nonce = 'myplugin-update-key';
}

2nd, we declare our newly generated random nonce into our POST form:

<form action= ...>
      <?php adsense_nonce_field('$myplugin_nonce', $myplugin_nonce); ?>
       ...

Finally, we check the nonce is correct in our $_POST request:

if ( isset($_POST['submit']) ) {
      if ( function_exists('current_user_can') && !current_user_can('manage_options') )
      die(__('Cheatin’ uh?'));

      check_admin_referer( '$myplugin_nonce', $adsense_nonce );

Each POST request will now contain a random number that is required in order to make the POST request. It is slightly more difficult to implement then the previous one, but not at all complicated when thought through.

You may have noticed that this addresses POST, but what about GET requests?

$delete_url = wp_nonce_url($get_url . "mode=del", '$adsense_nonce' . $myplugin_nonce);

The above will provide our nonce into the URL, now we just need to have it confirmed in our $_GET function:

if($mode == 'del' ){
    check_admin_referer('$myplugin_nonce', $myplugin_nonce);

And your done… now make sure to test it :)

Summary

It is vital for the security of future WordPress plugins that attribute_escape and wp_nonce functions be used to prevent critical vulnerabilities which currently affect many such plugins.

I encourage developers to modify their plugins to reflect these changes. Forgive me if their are blatent errors in the paper, I wrote it quite late while fixing a vulnerable plugin…well I’m off to bed.

References

WordPress Akismet Fixed

This is a quick alert to let everyone know that a new version of Akismet has been released to address the recent security vulnerability. As usual, I was very impressed with the speed and accuracy of WordPress in addressing this issue, in particular Ryan Boren and Matt Mullenweg.

For details on downloading the latest WordPress Akismet Plugin, please see: WordPress 2.1.3 Akismet Vulnerability.

I will wait a period of time to allow everyone to upgrade before releasing the full advisory, so keep an eye out for it.

WordPress 2.1.3 Akismet Vulnerability

Updates:
14/05/07 Added link to new version

David Kierznowski of Operation n has discovered a serious flaw in the Akismet anti-spam plugin that comes by default with the latest version of WordPress (2.1.3).

It has not been confirmed as yet, but I believe this will affect all versions of the plugin. The vendor has been notified, and more information regarding the vulnerability will be released when a suitable fix has been released.

I know its painful, but its recommended that you disable the Akismet plugin immediately.

The vendor was notified: 14/05/07
Response received: 14/05/07
Fix received: 14/05/07

The Akismet v2.0.2 Download upgrade has been made to address these issues and may be downloaded here.

Pitfalls of HTML Encryption

Michael observed the encrypted contents of the webpage with an immediate curiosity.

"Ars you can see Michael, we use HTML Code Guard to protect ur’ downloads page and to prevent spidurs’ and other automated programs from dawnloadin’ all ur’ products."

Michael tried to imagine how the developer across the phone looked. His voice was high-pitched, with a thick distinctive Irish accent.

The idea behind HTML Encryption is to prevent source code theft and to limit information leakage regarding the applications layout and structure.

HTML Encryption applications are designed to protect and secure HTML code. This post discusses a brief introduction to some of the weaknesses and pitfalls associated with HTML Encryption.

A snippet of encrypted HTML code (1 link) can be seen below:

<meta name="generator" content="HTML Code Guard" /><meta http-equiv="expires" content="0" /><script language="JavaScript"></script>

<!--<br /-->var d="b=~6,98a|6**.doo15;6=92:='p/,7|`*9+*bo=`";var fcrc="5DC10B9C";function dc(e){var ds="";e=e.toUpperCase();for(i=0;i<e.length;i+=2){ds+=unescape("%">

72657475726e206e6e3b7d66756e6374696f6e20686578286e756d297b7661722048657843686172732
03d202230313233343536373839414243444546223b76617220486578537472203d2022223b6e756d3d
61626e286e756d293b6966286e756d3d3d30292072657475726e20223030223b7768696c65286e756d3
e30297b486578537472203d2048657843686172732e636861724174286e756d25313629202b20486578
5374723b6e756d203d204d6174682e666c6f6f72286e756d2f3136293b7d72657475726e204865785374
723b7d66756e6374696f6e2043616c63435243333228737472297b766172206c696d69743d2d33303636
37343931322c206372632c204352435461626c653d6e657720417272617928293b666f7228693d303b693
c3d3235353b692b2b297b6372633d693b666f72286a3d303b6a3c3d373b6a2b2b297b6966286372632026
2031297b637263203d202828286372632026202d3229202f2032292026203231343734383336343729205
e206c696d69743b7d656c73657b637263203d2028286372632026202d3229202f203229202620323134373
438333634373b7d207d4352435461626c655b695d3d6372633b7d766172206372633d2d313b666f7228693
d303b693c7374722e6c656e6774682d313b692b2b297b637263203d202828286372632026202d32353629
202f2032353629202620313637373732313529205e20284352435461626c655b286372632026203235352
9205e207374722e63686172436f646541742869295d293b7d637263203d20637263205e202d313b6372633
d68657828637263293b6372633d6372632e746f55707065724361736528293b72657475726e2
</e.length;i+=2){ds+=unescape("%">

As seen above, its like finding a needle in a haystack. The encryption program above, utilises what I call the JavaScript chaos approach (as many do). This means the original code is pushed, obfuscated, pushed some more etc to prevent reverse engineering. When it is complete we are left with what you see above, a mess. Although, this is not readable to humans, it is obviously readable by the browser, it has to be, or the browser could never render it; however, this particular encryption application must have been designed and tested around Internet Explorer, as Firefox dies and enters an infinite loop when its JavaScript engine attempts to render this. This is our first pitfall when utilising these programs: The large amount of JavaScript obfuscation may cause unexpected results with various browsers.

Second, without attempting to reverse enginner the code (to make it normal HTML once again), we can simply use the browser DOM (Document Object Model) to pry open the websites contents. It is trivial to retrieve images, links, CSS, forms, tables etc. For example, to retrieve the first link on the page, we could simply do this from the navigation bar:

javascript:var x=document.getElementsByTagName('A');alert(x[0].href);

The outcome:

This was me playing around for 10 minutes (literally). In summary… erm.. need I say more.

Michael Daw Anthology

michaeldaw.org is pleased to announce the first “Michael Daw Anthology” award.

For those of you curious, anthology is a collection of published works. The original idea behind the michaeldaw.org website was to build stories upon a fictional hacking icon named, Michael Daw, as well as to host other security related material. As a close friend pointed out to me, the name is very relevant "when pondered upon". Some believe that the archangel Michael holds the keys to the doors of Heaven.

Use cutting-edge security wizardry, use sci-fi… write a hacking story centered around Michael Daw and be 1 of 6 to stand the chance of winning.

The full details of the competition will be provided soon. We are currently seeking sponsors to donate towards the winnings. For more information please contact us.

They say there is a story in each of us…

« Previous PageNext Page »

Recent