CVE-2017-9435: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: Dolibarr ERP/CRM before 5.0.3 is vulnerable to a SQL injection in user/index.php (search_supervisor and search_statut parameters).
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
CVSS v3 base score: 9.8
Published: 2017-06-05T14:29Z
Repository: https://github.com/Dolibarr/dolibarr
Language: PHP
Files changed: htdocs/core/lib/functions.lib.php, htdocs/user/index.php
Commit date: 2017-05-29 09:59:21 +0200
Commit message: FIX SQL injection on user/index.php parameter search_statut.
Diff: diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 2db8ecdb111..c678e0bc7df 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -284,10 +284,13 @@ function GETPOST($paramname,$check='',$method=0,$filter=NULL,$options=NULL)
 	    switch ($check)
 	    {
 	        case 'int':
 	            if (! is_numeric($out)) { $out=''; }
 	            break;
+	        case 'intcomma':
+	            if (preg_match('/[^0-9,]+/i',$out)) $out='';
+	            break;
 	        case 'alpha':
 	            $out=trim($out);
 	            // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
 	            // '../' is dangerous because it allows dir transversals
 	            if (preg_match('/"/',$out)) $out='';
diff --git a/htdocs/user/index.php b/htdocs/user/index.php
index 9e7c78f9799..35a05ad4be1 100644
--- a/htdocs/user/index.php
+++ b/htdocs/user/index.php
@@ -117,13 +117,13 @@ $search_lastname=GETPOST('search_lastname','alpha');
 $search_firstname=GETPOST('search_firstname','alpha');
 $search_gender=GETPOST('search_gender','alpha');
 $search_employee=GETPOST('search_employee','alpha');
 $search_accountancy_code=GETPOST('search_accountancy_code','alpha');
 $search_email=GETPOST('search_email','alpha');
-$search_statut=GETPOST('search_statut','alpha');
+$search_statut=GETPOST('search_statut','intcomma');
 $search_thirdparty=GETPOST('search_thirdparty','alpha');
-$search_supervisor=GETPOST('search_supervisor','alpha');
+$search_supervisor=GETPOST('search_supervisor','intcomma');
 $search_previousconn=GETPOST('search_previousconn','alpha');
 $optioncss = GETPOST('optioncss','alpha');
 
 // Default search
 if ($search_statut == '') $search_statut='1';
@@ -146,11 +146,11 @@ if (empty($reshook))
 {
     // Selection of new fields
     include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
 
     // Purge search criteria
-    if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
+    if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
     {
     	$search_user="";
     	$search_login="";
     	$search_lastname="";
     	$search_firstname="";
@@ -201,23 +201,23 @@ else
 {
 	$sql.= " WHERE u.entity IN (".getEntity('user',1).")";
 }
 if ($socid > 0) $sql.= " AND u.fk_soc = ".$socid;
 //if ($search_user != '')       $sql.=natural_search(array('u.login', 'u.lastname', 'u.firstname'), $search_user);
-if ($search_supervisor > 0)   $sql.= " AND u.fk_user = ".$search_supervisor;
-if ($search_thirdparty != '') $sql.=natural_search(array('s.nom'), $search_thirdparty);
+if ($search_supervisor > 0)   $sql.= " AND u.fk_user = ".$db->escape($search_supervisor);
+if ($search_thirdparty != '') $sql.= natural_search(array('s.nom'), $search_thirdparty);
 if ($search_login != '')      $sql.= natural_search("u.login", $search_login);
 if ($search_lastname != '')   $sql.= natural_search("u.lastname", $search_lastname);
 if ($search_firstname != '')  $sql.= natural_search("u.firstname", $search_firstname);
 if ($search_gender != '' && $search_gender != '-1')     $sql.= " AND u.gender = '".$search_gender."'";
 if (is_numeric($search_employee) && $search_employee >= 0)    {
 	$sql .= ' AND u.employee = '.(int) $search_employee;
 }
 if ($search_accountancy_code != '')  $sql.= natural_search("u.accountancy_code", $search_accountancy_code);
-if ($search_email != '')  $sql.= natural_search("u.email", $search_email);
-if ($search_statut != '' && $search_statut >= 0) $sql.= " AND (u.statut=".$search_statut.")";
-if ($sall)                    $sql.= natural_search(array_keys($fieldstosearchall), $sall);
+if ($search_email != '')             $sql.= natural_search("u.email", $search_email);
+if ($search_statut != '' && $search_statut >= 0) $sql.= " AND u.statut IN (".$db->escape($search_statut).")";
+if ($sall)                           $sql.= natural_search(array_keys($fieldstosearchall), $sall);
 // Add where from extra fields
 foreach ($search_array_options as $key => $val)
 {
     $crit=$val;
     $tmpkey=preg_replace('/search_options_/','',$key);

Vulnerable code: $search_statut=GETPOST('search_statut','alpha');
$search_supervisor=GETPOST('search_supervisor','alpha');
    if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
if ($search_supervisor > 0)   $sql.= " AND u.fk_user = ".$search_supervisor;
if ($search_thirdparty != '') $sql.=natural_search(array('s.nom'), $search_thirdparty);
if ($search_email != '')  $sql.= natural_search("u.email", $search_email);
if ($search_statut != '' && $search_statut >= 0) $sql.= " AND (u.statut=".$search_statut.")";
if ($sall)                    $sql.= natural_search(array_keys($fieldstosearchall), $sall);
Fixed code: 	        case 'intcomma':
	            if (preg_match('/[^0-9,]+/i',$out)) $out='';
	            break;
$search_statut=GETPOST('search_statut','intcomma');
$search_supervisor=GETPOST('search_supervisor','intcomma');
    if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
if ($search_supervisor > 0)   $sql.= " AND u.fk_user = ".$db->escape($search_supervisor);
if ($search_thirdparty != '') $sql.= natural_search(array('s.nom'), $search_thirdparty);
if ($search_email != '')             $sql.= natural_search("u.email", $search_email);
if ($search_statut != '' && $search_statut >= 0) $sql.= " AND u.statut IN (".$db->escape($search_statut).")";
if ($sall)                           $sql.= natural_search(array_keys($fieldstosearchall), $sall);