Details
Affected Software:The Hacker’s Diet (WordPress Plugin)
Fixed in Version:0.9.7b
Issue Type:SQL Injection
Original Code: Found Here
Description
This week’s vulnerability was a SQL injection vulnerability affecting the Hacker’s Diet WordPress plugin. In the vulnerable version,the plugin assigns several variables using values obtained directly from the querystring. The variable assignments are shown below:
$weeks = $_GET["weeks"];
$start_date = $_GET["start_date"];
$end_date = $_GET["end_date"];
$goal = $_GET["goal"];
$user_id = $_GET["user"];
$maint_mode = $_GET["maint_mode"];
No sanitization or validation is done before assigning the values. Once the assignments are made,the attacker controlled values are then passed to a dynamic SQL string here resulting in SQL Injection:
$query = “select date,weight,trend from “.$table_prefix.”hackdiet_weightlog where wp_id = $user_id and date >\”".date(“Y-m-d”,strtotime(“$weeks weeks ago”)).”\”order by date asc”;
$query = “select date,weight,trend from “.$table_prefix.”hackdiet_weightlog where wp_id = $user_id and date >= \”$start_date\”and date <= \”$end_date\”order by date asc”;
The plugin authors patched this vulnerability by validating that the $_GET[“user”] and $_GET[“weeks”] parameters contains only numeric characters. An interesting exercise would be to trace through the code and find where the following variables are being used:
$start_date = $_GET["start_date"];
$end_date = $_GET["end_date"];
$goal = $_GET["goal"];
$maint_mode = $_GET["maint_mode"];
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | <?php include (dirname(__FILE__)."/jpgraph/jpgraph.php"); include (dirname(__FILE__)."/jpgraph/jpgraph_line.php"); include (dirname(__FILE__)."/jpgraph/jpgraph_scatter.php"); // get our db settings without loading all of wordpress every save $html = implode('',file("../../../wp-config.php")); $html = str_replace ("require_once","// ",$html); $html = str_replace ("<?php","",$html); $html = str_replace ("?>","",$html); eval($html); mysql_connect(DB_HOST,DB_USER,DB_PASSWORD); mysql_select_db(DB_NAME); +if (!is_numeric($_GET["user"]) || !is_numeric($_GET["weeks"])) { + exit; +} $weeks = $_GET["weeks"]; $start_date = $_GET["start_date"]; $end_date = $_GET["end_date"]; $goal = $_GET["goal"]; $user_id = $_GET["user"]; $maint_mode = $_GET["maint_mode"]; if ($weeks) { - $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = $user_id and date >\"".date("Y-m-d",strtotime("$weeks weeks ago"))."\"order by date asc"; + $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = \"". $user_id . "\"and date >\"".date("Y-m-d",strtotime("$weeks weeks ago"))."\"order by date asc"; } else if ($start_date and $end_date) { - $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = $user_id and date >= \"$start_date\"and date <= \"$end_date\"order by date asc"; + $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = \"". $user_id . "\"and date >= \"$start_date\"and date <= \"$end_date\"order by date asc"; } result = mysql_query($query); if (mysql_num_rows($result)) { if (mysql_num_rows($result) == 1) { // only one day,gotta finagle the display $row = mysql_fetch_assoc($result); // fake day before $weight_data[] = 0; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime("yesterday",strtotime($row["date"]))); // data $weight_data[] = $row["weight"]; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime($row["date"])); // fake day after $weight_data[] = 0; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime("tomorrow",strtotime($row["date"]))); } else { $num_rows = mysql_num_rows($result); if ($num_rows <= 7 * 2) { // 0-2 weeks $ticks = "daily"; } else if ($num_rows <= 31 * 4) { // 2 weeks - 4 months $ticks = "weekly"; } else { // 4 months + $ticks = "monthly"; } $count = 1; while ($row = mysql_fetch_assoc($result)) { $weight_data[] = $row["weight"]; $trend_data[] = $row["trend"]; if ($goal >0) { $goal_data[] = $goal; } switch ($ticks) { case "weekly": if ($count == 1) { $x_data[] = date("n/j",strtotime($row["date"])); } else { $x_data[] = ""; if ($count == 7) { $count = 0; } } break; case "monthly": if (date("j",strtotime($row["date"])) == "1") { $x_data[] = date("n/j",strtotime($row["date"])); } else { $x_data[] = ""; } break; case "daily": default: $x_data[] = date("n/j",strtotime($row["date"])); break; } $count++; } } |


