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++; } } |



