CVE-2017-14242: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: SQL injection vulnerability in don/list.php in Dolibarr version 6.0.0 allows remote attackers to execute arbitrary SQL commands via the statut parameter.
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-09-11T09:29Z
Repository: https://github.com/Dolibarr/dolibarr
Language: PHP
Files changed: htdocs/core/lib/functions.lib.php, htdocs/don/card.php, htdocs/don/document.php, htdocs/don/info.php, htdocs/don/list.php, htdocs/don/note.php, htdocs/install/mysql/migration/5.0.0-6.0.0.sql
Commit date: 2017-09-06 18:17:57 +0200
Commit message: FIX SQL injection
Diff: diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index ee683f5747d..b1ab8280c66 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -6197,10 +6197,12 @@ function dol_getmypid()
  */
 function natural_search($fields, $value, $mode=0, $nofirstand=0)
 {
     global $db,$langs;
 
+    $value=trim($value);
+
     if ($mode == 0)
     {
     	$value=preg_replace('/\*/','%',$value);	// Replace * with %
     }
     if ($mode == 1)
diff --git a/htdocs/don/card.php b/htdocs/don/card.php
index 203c35caa72..72ea8e84792 100644
--- a/htdocs/don/card.php
+++ b/htdocs/don/card.php
@@ -343,21 +343,21 @@ if ($action == 'create')
 
 	print "<tr>".'<td>'.$langs->trans("EMail").'</td><td><input type="text" name="email" value="'.dol_escape_htmltag(GETPOST("email")).'" class="maxwidth200"></td></tr>';
 
 	// Public note
 	print '<tr>';
-	print '<td class="border" valign="top">' . $langs->trans('NotePublic') . '</td>';
+	print '<td class="tdtop">' . $langs->trans('NotePublic') . '</td>';
 	print '<td>';
 
     $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%');
 	print $doleditor->Create(1);
 	print '</td></tr>';
 
 	// Private note
 	if (empty($user->societe_id)) {
 		print '<tr>';
-		print '<td class="border" valign="top">' . $langs->trans('NotePrivate') . '</td>';
+		print '<td class="tdtop">' . $langs->trans('NotePrivate') . '</td>';
 		print '<td>';
 
 		$doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%');
 		print $doleditor->Create(1);
 		print '</td></tr>';
@@ -540,11 +540,11 @@ if (! empty($id) && $action != 'edit')
 	}
 
 	$hselected='card';
 
 	$head = donation_prepare_head($object);
-	dol_fiche_head($head, $hselected, $langs->trans("Donation"), 0, 'generic');
+	dol_fiche_head($head, $hselected, $langs->trans("Donation"), -1, 'generic');
 
 	// Print form confirm
 	print $formconfirm;
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/don/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>';
diff --git a/htdocs/don/document.php b/htdocs/don/document.php
index 115f58e5cc1..0ae81231bc1 100644
--- a/htdocs/don/document.php
+++ b/htdocs/don/document.php
@@ -102,11 +102,11 @@ if ($object->id)
 {
 	$object->fetch_thirdparty();
 
 	$head=donation_prepare_head($object);
 
-	dol_fiche_head($head, 'documents',  $langs->trans("Donation"), 0, 'generic');
+	dol_fiche_head($head, 'documents',  $langs->trans("Donation"), -1, 'generic');
 
 
 	// Construit liste des fichiers
 	$filearray=dol_dir_list($upload_dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
 	$totalsize=0;
@@ -114,11 +114,11 @@ if ($object->id)
 	{
 		$totalsize+=$file['size'];
 	}
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/don/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>';
-	
+
 	$morehtmlref='<div class="refidno">';
 	// Project
 	if (! empty($conf->projet->enabled))
 	{
 	    $langs->load("projects");
@@ -149,37 +149,37 @@ if ($object->id)
 	            $morehtmlref.='';
 	        }
 	    }
 	}
 	$morehtmlref.='</div>';
-	
-	
+
+
 	dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref);
-	
+
 	print '<div class="fichecenter">';
 	print '<div class="underbanner clearboth"></div>';
-	
+
     print '<table class="border" width="100%">';
 
 	// Ref
 	/*
 	print '<tr><td class="titlefield">'.$langs->trans("Ref").'</td><td>';
 	print $form->showrefnav($object, 'id', $linkback, 1, 'rowid', 'ref', '');
 	print '</td></tr>';
     */
-    
+
 	// Societe
 	//print "<tr><td>".$langs->trans("Company")."</td><td>".$object->client->getNomUrl(1)."</td></tr>";
 
     print '<tr><td class="titlefield">'.$langs->trans("NbOfAttachedFiles").'</td><td colspan="3">'.count($filearray).'</td></tr>';
     print '<tr><td>'.$langs->trans("TotalSizeOfAttachedFiles").'</td><td colspan="3">'.$totalsize.' '.$langs->trans("bytes").'</td></tr>';
     print '</table>';
 
     print '</div>';
-    
+
     print '<div class="clearboth"></div>';
-    
+
     dol_fiche_end();
 
     $modulepart = 'don';
     $permission = $user->rights->don->lire;
     $permtoedit = $user->rights->don->creer;
diff --git a/htdocs/don/info.php b/htdocs/don/info.php
index 46f398d4749..30c2129b6c6 100644
--- a/htdocs/don/info.php
+++ b/htdocs/don/info.php
@@ -65,11 +65,11 @@ if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); }
 
 $object->info($id);
 
 $head = donation_prepare_head($object);
 
-dol_fiche_head($head, 'info', $langs->trans("Donation"), 0, 'generic');
+dol_fiche_head($head, 'info', $langs->trans("Donation"), -1, 'generic');
 
 $linkback = '<a href="'.DOL_URL_ROOT.'/don/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>';
 
 $morehtmlref='<div class="refidno">';
 // Project
@@ -114,11 +114,11 @@ print '<div class="underbanner clearboth"></div>';
 print '<br>';
 
 print '<table width="100%"><tr><td>';
 dol_print_object_info($object);
 print '</td></tr></table>';
-      
+
 print '</div>';
 
 dol_fiche_end();
 
 llxFooter();
diff --git a/htdocs/don/list.php b/htdocs/don/list.php
index 3d0422da917..5521b233a28 100644
--- a/htdocs/don/list.php
+++ b/htdocs/don/list.php
@@ -40,11 +40,11 @@ $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
 if (! $sortorder) $sortorder="DESC";
 if (! $sortfield) $sortfield="d.datedon";
 
-$statut=isset($_GET["statut"])?$_GET["statut"]:"-1";
+$statut=(GETPOST("statut",'intcomma')!='')?GETPOST("statut",'intcomma'):"-1";
 $search_all=GETPOST('sall', 'alphanohtml');
 $search_ref=GETPOST('search_ref','alpha');
 $search_company=GETPOST('search_company','alpha');
 $search_name=GETPOST('search_name','alpha');
 $search_amount = GETPOST('search_amount','alpha');
@@ -88,17 +88,17 @@ $donationstatic=new Don($db);
 $sql = "SELECT d.rowid, d.datedon, d.firstname, d.lastname, d.societe,";
 $sql.= " d.amount, d.fk_statut as statut, ";
 $sql.= " p.rowid as pid, p.ref, p.title, p.public";
 $sql.= " FROM ".MAIN_DB_PREFIX."don as d LEFT JOIN ".MAIN_DB_PREFIX."projet AS p";
 $sql.= " ON p.rowid = d.fk_projet WHERE 1 = 1";
-if ($statut >= 0)
+if ($statut != '' && $statut != '-1')
 {
-	$sql .= " AND d.fk_statut = ".$statut;
+	$sql .= " AND d.fk_statut IN (".$statut.")";
 }
 if (trim($search_ref) != '')
 {
-    $sql.= ' AND d.rowid LIKE \'%'.$db->escape(trim($search_ref)) . '%\'';
+    $sql.= natural_search('d.ref',$search_ref);
 }
 if (trim($search_all) != '')
 {
     $sql .= natural_search(array_keys($fieldstosearchall), $search_all);
 }
@@ -108,11 +108,11 @@ if (trim($search_company) != '')
 }
 if (trim($search_name) != '')
 {
     $sql .= natural_search(array('d.lastname', 'd.firstname'), $search_name);
 }
-if ($search_amount) $sql.= natural_search(array('d.amount'), price2num(trim($search_amount)), 1);
+if ($search_amount) $sql.= natural_search('d.amount', $search_amount, 1);
 
 $sql.= $db->order($sortfield,$sortorder);
 $nbtotalofrecords = '';
 if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 {
@@ -129,21 +129,11 @@ if ($resql)
 
 	$param = '&statut='.$statut;
     //if ($page > 0) $param.= '&page='.$page;
 	if ($optioncss != '') $param.='&optioncss='.$optioncss;
 
-	if ($statut >= 0)
-	{
-	    $donationstatic->statut=$statut;
-	    $label=$donationstatic->getLibStatut(0);
-		print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
-	}
-	else
-	{
-		print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
-	}
-
+	print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
 
     print '<form method="get" action="'.$_SERVER["PHP_SELF"].'">'."\n";
     if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
 	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 	print '<input type="hidden" name="action" value="list">';
diff --git a/htdocs/don/note.php b/htdocs/don/note.php
index b197510a585..d78aa2c7ea5 100644
--- a/htdocs/don/note.php
+++ b/htdocs/don/note.php
@@ -82,11 +82,11 @@ if ($id > 0 || ! empty($ref))
 	$object = new Don($db);
 	$object->fetch($id,$ref);
 
 	$head = donation_prepare_head($object);
 
-	dol_fiche_head($head, 'note', $langs->trans("Donation"), 0, 'generic');
+	dol_fiche_head($head, 'note', $langs->trans("Donation"), -1, 'generic');
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/don/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>';
 
 	$morehtmlref='<div class="refidno">';
 	// Project
diff --git a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
index f6a2c18da82..4567d160cc2 100644
--- a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
+++ b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
@@ -22,10 +22,12 @@
 -- To set a field as default NULL:             -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name SET DEFAULT NULL;
 -- Note: fields with type BLOB/TEXT can't have default value.
 -- -- VPGSQL8.2 DELETE FROM llx_usergroup_user      WHERE fk_user      NOT IN (SELECT rowid from llx_user);
 -- -- VMYSQL4.1 DELETE FROM llx_usergroup_user      WHERE fk_usergroup NOT IN (SELECT rowid from llx_usergroup);
 
+
+
 ALTER TABLE llx_holiday_config MODIFY COLUMN name varchar(128);
 
 ALTER TABLE llx_supplier_proposaldet CHANGE COLUMN fk_askpricesupplier fk_supplier_proposal integer NOT NULL;
 
 -- VMYSQL4.1 SET sql_mode = 'ALLOW_INVALID_DATES';
@@ -324,11 +326,12 @@ ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_invoic
 ALTER TABLE llx_facture_rec ADD COLUMN vat_src_code	varchar(10) DEFAULT '';
 ALTER TABLE llx_expensereport_det ADD COLUMN vat_src_code varchar(10)  DEFAULT '';
 
 DELETE FROM llx_const WHERE name = __ENCRYPT('ADHERENT_BANK_USE_AUTO')__;
 
-UPDATE llx_const SET value = __ENCRYPT('moono-lisa')__ WHERE value = __ENCRYPT('moono')__ AND name = __ENCRYPT('FCKEDITOR_SKIN')__;
+UPDATE llx_const SET value = __ENCRYPT('moono-lisa')__   WHERE value = __ENCRYPT('moono')__       AND name = __ENCRYPT('FCKEDITOR_SKIN')__;
+DELETE FROM llx_document_model where nom = 'fsfe.fr.php' and type='donation';
 
 ALTER TABLE llx_product_price ADD COLUMN default_vat_code	varchar(10) AFTER tva_tx;
 ALTER TABLE llx_product_fournisseur_price ADD COLUMN default_vat_code	varchar(10) AFTER tva_tx;
 
 ALTER TABLE llx_user ADD COLUMN model_pdf varchar(255);

Vulnerable code: 	print '<td class="border" valign="top">' . $langs->trans('NotePublic') . '</td>';
		print '<td class="border" valign="top">' . $langs->trans('NotePrivate') . '</td>';
	dol_fiche_head($head, $hselected, $langs->trans("Donation"), 0, 'generic');
	dol_fiche_head($head, 'documents',  $langs->trans("Donation"), 0, 'generic');
	
	
	
	
	
    
    
    
dol_fiche_head($head, 'info', $langs->trans("Donation"), 0, 'generic');
      
$statut=isset($_GET["statut"])?$_GET["statut"]:"-1";
if ($statut >= 0)
	$sql .= " AND d.fk_statut = ".$statut;
    $sql.= ' AND d.rowid LIKE \'%'.$db->escape(trim($search_ref)) . '%\'';
if ($search_amount) $sql.= natural_search(array('d.amount'), price2num(trim($search_amount)), 1);
	if ($statut >= 0)
	{
	    $donationstatic->statut=$statut;
	    $label=$donationstatic->getLibStatut(0);
		print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
	}
	else
	{
		print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
	}

	dol_fiche_head($head, 'note', $langs->trans("Donation"), 0, 'generic');
UPDATE llx_const SET value = __ENCRYPT('moono-lisa')__ WHERE value = __ENCRYPT('moono')__ AND name = __ENCRYPT('FCKEDITOR_SKIN')__;
Fixed code:     $value=trim($value);

	print '<td class="tdtop">' . $langs->trans('NotePublic') . '</td>';
		print '<td class="tdtop">' . $langs->trans('NotePrivate') . '</td>';
	dol_fiche_head($head, $hselected, $langs->trans("Donation"), -1, 'generic');
	dol_fiche_head($head, 'documents',  $langs->trans("Donation"), -1, 'generic');








dol_fiche_head($head, 'info', $langs->trans("Donation"), -1, 'generic');

$statut=(GETPOST("statut",'intcomma')!='')?GETPOST("statut",'intcomma'):"-1";
if ($statut != '' && $statut != '-1')
	$sql .= " AND d.fk_statut IN (".$statut.")";
    $sql.= natural_search('d.ref',$search_ref);
if ($search_amount) $sql.= natural_search('d.amount', $search_amount, 1);
	print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num,$nbtotalofrecords);
	dol_fiche_head($head, 'note', $langs->trans("Donation"), -1, 'generic');


UPDATE llx_const SET value = __ENCRYPT('moono-lisa')__   WHERE value = __ENCRYPT('moono')__       AND name = __ENCRYPT('FCKEDITOR_SKIN')__;
DELETE FROM llx_document_model where nom = 'fsfe.fr.php' and type='donation';