AppSec Blog

Spot the Vuln - Wood - SQL injection


Affected Software: WordPress Core

Fixed in Version: 2.2

Issue Type: SQL Injection

Original Code: Found Here


This is a fairly straight forward SQL Injection bug here. First, although we can't see exactly where $args[] is set, we have some strong clues that it contains user/attacker controlled data. For example, the first function on the code snippet wp_newCategory() takes an $args parameter and the first thing it does is escape the values within the array. The names of variables holding various values in the array also provide clues that $args cannot be trusted.

On line 66 we see that $max_results is assigned the value from $args[4]. $max_results is then used to build a portion of a SQL string which is assigned to the $limit variable. $limit is then passed to the end of a SQL statement on line 84, resulting in SQL injection. Some readers may point out that $args is escaped in on line 60, before it is used to build any SQL statement. Unfortunately, escaping values in this case doesn't prevent SQL injection. The attacker controlled value is eventually used to build a LIMIT clause. The LIMIT clause doesn't enclose the attacker supplied values within quotes, so there are no quotes to break out of.

The developers addressed this issue by casting args[4] to int during assignment to $max_results. If args[4] contains any characters that do not qualify as an integer, the value will not be passed to the LIMIT statement.

Developers Solution

<?php ...snip... function wp_newCategory($args) { $this->escape($args); $blog_id= (int) $args[0]; $username= $args[1]; $password= $args[2]; $category= $args[3]; if(!$this->login_pass_ok($username, $password)) { return($this->error); } // Set the user context and make sure they are // allowed to add a category. set_current_user(0, $username); if(!current_user_can("manage_categories", $page_id)) { return(new IXR_Error(401, __("Sorry, you do not have the right to add a category."))); } // We need this to make use of the wp_insert_category() // funciton. require_once(ABSPATH . "wp-admin/admin-db.php"); // If no slug was provided make it empty so that // WordPress will generate one. if(empty($category["slug"])) { $category["slug"] = ""; } // If no parent_id was provided make it empty // so that it will be a top level page (no parent). if ( !isset($category["parent_id"]) ) $category["parent_id"] = ""; // If no description was provided make it empty. if(empty($category["description"])) { $category["description"] = ""; } $new_category = array( "cat_name"=> $category["name"], "category_nicename"=> $category["slug"], "category_parent"=> $category["parent_id"], "category_description"=> $category["description"] ); $cat_id = wp_insert_category($new_category); if(!$cat_id) { return(new IXR_Error(500, __("Sorry, the new category failed."))); } return($cat_id); } function wp_suggestCategories($args) { global $wpdb; $this->escape($args); $blog_id= (int) $args[0]; $username= $args[1]; $password= $args[2]; $category= $args[3]; -$max_results= $args[4]; +$max_results = (int) $args[4]; if(!$this->login_pass_ok($username, $password)) { return($this->error); } // Only set a limit if one was provided. $limit = ""; if(!empty($max_results)) { $limit = "LIMIT {$max_results}"; } $category_suggestions = $wpdb->get_results(" SELECT cat_ID category_id, cat_name category_name FROM {$wpdb->categories} WHERE cat_name LIKE '{$category}%' {$limit} "); return($category_suggestions); } /* Blogger API functions * specs on and */ /* blogger.getUsersBlogs will make more sense once we support multiple blogs */ function blogger_getUsersBlogs($args) { $this->escape($args); $user_login = $args[1]; $user_pass = $args[2]; if (!$this->login_pass_ok($user_login, $user_pass)) { return $this->error; } set_current_user(0, $user_login); $is_admin = current_user_can('level_8'); $struct = array( 'isAdmin' => $is_admin, 'url' => get_option('home') . '/', 'blogid' => '1', 'blogName' => get_option('blogname') ); return array($struct); } ...snip... ?> ...snip...

Post a Comment


* Indicates a required field.