views:

49

answers:

2

I have a wordpress theme with an options page. I have included a basic export/import options feature. The export feature allows the users to download the options to a text .dat file and store them on their own computer. The import options button reads a .dat file and overwrites the current options in the database. Then the file is deleted at the end of script execution (not stored in the server).

There are no separate uploads.php files, everything happens in one script (the export, import, etc).

I tried importing some php files, and other types of files, and the only thing that happened was the options were wiped out. But that's what's supposed to happen, the imported file is supposed to replace whatever is in the database.

The user can only access this form if they are logged in to the WordPress Dashboard with admin access.

So there is no need to have extensive security features on this import form, is there? Except, maybe I should try it with .sql files and see what could happen? Could someone potentially create an .sql file and wipeout the entire database? Should I blacklist .sql files to be safe?

Here is my import code:

   if ( $_GET['page'] == basename(__FILE__) ) {
        if ( 'export' == $_POST['action']) {
        cpress_export();
    }   
    if (isset($_FILES['settings'])){
        if ($_FILES["settings"]["error"] > 0){
            echo "Error: " . $_FILES["settings"]["error"] . "<br />";
          } else{
            $rawdata = file_get_contents($_FILES["settings"]["tmp_name"]);
            $cp_options = unserialize($rawdata);
            update_option('cpress_options', $cp_options);
            header("Location: themes.php?page=options_page.php&import=true");
          }
    }

And here is my export code (in the same file):

function cpress_export(){
$settings = get_option('cpress_options');
$file_out = serialize($settings);
header("Cache-Control: public, must-revalidate");
header("Pragma: hack"); 
header("Content-type: text/plain; charset=ISO-8859-1");
header('Content-Disposition: attachment; filename="cpress-options-'.date("Ymd").'.dat"');
echo $file_out;
exit;}
+2  A: 

If you are reading from a file and loading that file into the database, then there is an opportunity for exploitation, sure. However, if this is only enabled for admins, then I don't know how much effort should be put in to protecting against malicious activity. If they are admins, there are much easier things they could do to wipe out the database.

As a general rule, it is probably worth some effort to making it so users can't accidentally screw anything up, but keeping your admin users from doing malicious things is neither worth the effort nor consistent with the idea of an "admin" role. It is like giving someone su privileges on a Linux box and trying to make sure they can't install malicious software on it.

edit:I checked the Wordpress docs, and the update_option() function escapes the string before the query is run. You should be safe from SQL injections.

Jergason
Yeah...but is there any way that a hacker who is not an admin could potentially get access to the options page without even having to login? Using PHP Shells or something? If I try to go directly to the options page via my browser, I get a 404...so that's a good thing, right?
orbit82
Sure, potentially. There might be some WordPress vulnerabilities that allow an unauthorized user to gain admin access.
Jergason
+2  A: 

A couple of improvements I'd recommend;

  1. Use if (!defined('ABSPATH')) die() at the beginning of your plugin - if a malicious user tried to load your script directly, it would fail, since the WordPress constant ABSPATH isn't defined.

  2. Use WordPress nonces - this will at least make a nasty person's life a little harder :)

  3. Check that unserialize() does not fail (the result will be boolean false if it does) - this will happen if the serialized data was malformed (or wasn't serialized to begin with). If it fails, don't proceed with the update.

  4. Use wp_safe_redirect() instead of header() for your redirect (in fact, you should always use this function when redirecting to other WP admin pages - otherwise use wp_redirect()).

TheDeadMedic
Thanks so much for those tips!
orbit82