Popular Vulnerable Code

More Than One Night - Defense in DepthMore Than One Night – Defense in Depth

Details

Affected Software:WordPress

Fixed in Version:2.1

Issue Type:Defense in Depth

Original Code: Found Here

Description

I found this issue interesting for a couple reasons. Upon first glance,the patch appears to be a defense against SQL Injection and in essence,it is. It seems that the $q[‘cat’] value is controlled by the user and is eventually used to help build a SQL statement. Before the $q[‘cat’] value is used in a SQL statement,it is actually sanitized by the following lines:

$q['cat'] = ”.urldecode($q['cat']).”;

$q['cat'] = addslashes_gpc($q['cat']);

Once the value is sanitized,it is used to build various SQL statements. Now this particular patch was developed by the WordPress team because they discovered that when a user/attacker passes a “.” (period character) to $q[‘cat’],it would cause a SQL error which would be displayed to the user. While a single period character doesn’t give the attacker the ability to execute arbitrary SQL,it does give the attacker an information disclosure bug. In an academic sense however,the attacker has convinced the database that their provided value should be interpreted as code as opposed to data (ala SQL Injection). The reason the period character slips through is because it is not defined as a special character in the addslashes() php function… this could be useful in other situations.

The WordPress prevented the information leak by checking to see if $q[‘cat’] is an integer value. The patch here is a single line fix.

Developers Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Category stuff

if ((empty($q['cat'])) || ($q['cat'] == '0') ||

// Bypass cat checks if fetching specific posts

( $this->is_single || $this->is_page )) {

$whichcat='';

} else {

$q['cat'] = ''.urldecode($q['cat']).'';

$q['cat'] = addslashes_gpc($q['cat']);

$join = "LEFT JOIN $wpdb->post2cat ON ($wpdb->posts.ID = $wpdb->post2cat.post_id) ";

$cat_array = preg_split('/[,\s]+/',$q['cat']);

$in_cats = $out_cats = '';

foreach ( $cat_array as $cat ) {

+ $cat = intval($cat);

$in = strstr($cat,'-') ? false:true;

$cat = trim($cat,'-');

if ( $in )

$in_cats .= "$cat,". get_category_children($cat,'',',');

else

$out_cats .= "$cat,". get_category_children($cat,'',',');

}

$in_cats = substr($in_cats,0,-2);

$out_cats = substr($out_cats,0,-2);

if ( strlen($in_cats) >0 )

$in_cats = "AND category_id IN ($in_cats)";

if ( strlen($out_cats) >0 )

$out_cats = "AND category_id NOT IN ($out_cats)";

$whichcat = $in_cats . $out_cats;

$distinct = 'DISTINCT';

}

// Category stuff for nice URIs

global $cache_categories;

if ('' != $q['category_name']) {