CVE-2018-13448 (PHP, published 2018-07-08T16:29Z)
Description: value: SQL injection vulnerability in product/card.php in Dolibarr ERP/CRM version 7.0.3 allows remote attackers to execute arbitrary SQL commands via the country_id parameter.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
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.
Repository: https://github.com/Dolibarr/dolibarr
Files changed:
htdocs/core/class/html.form.class.php
htdocs/main.inc.php
htdocs/product/card.php
htdocs/societe/ajax/company.php
Commit message: FIX SQL Injections reported by mu shcor (ADLab of Venustech)

Vulnerable code:
	 *  @param  string	$filter         optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
 * @param		string		$type		1=GET, 0=POST, 2=PHP_SELF
	if ($type == 1)
		$inj += preg_match('/updatexml\(/i',	 $val);
	if ($type != 2)	// Not common, we can check on POST
		//unset($form);

            $object->customcode              = GETPOST('customcode');
            $object->country_id              = GETPOST('country_id');
            $object->finished           	 = GETPOST('finished');
	        $object->fk_unit                 = GETPOST('units');
			$accountancy_code_sell 			 = GETPOST('accountancy_code_sell');
			$accountancy_code_sell_intra	 = GETPOST('accountancy_code_sell_intra');
			$accountancy_code_sell_export	 = GETPOST('accountancy_code_sell_export');
			$accountancy_code_buy 			 = GETPOST('accountancy_code_buy');
                $object->customcode             = GETPOST('customcode');
                $object->country_id             = GETPOST('country_id');
                $object->status                 = GETPOST('statut');
                $object->status_buy             = GETPOST('statut_buy');
                $object->status_batch	        = GETPOST('status_batch');
                $object->finished               = GETPOST('finished');
				$accountancy_code_sell 			 = GETPOST('accountancy_code_sell');
				$accountancy_code_sell_intra	 = GETPOST('accountancy_code_sell_intra');
				$accountancy_code_sell_export	 = GETPOST('accountancy_code_sell_export');
				$accountancy_code_buy 			 = GETPOST('accountancy_code_buy');
			if ($conf->productbatch->enabled) 
            if (! empty($conf->productbatch->enabled)) 
	$form = new Form($db);

Fixed code:
	 *  @param  string	$filter         Optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
		// Clean $filter that may contains sql conditions so sql code
		if (function_exists('test_sql_and_script_inject')) $filter = test_sql_and_script_inject($filter, 3);

 * @param		string		$type		1=GET, 0=POST, 2=PHP_SELF, 3=GET without sql reserved keywords (the less tolerant test)
	if ($type == 1 || $type == 3)
		$inj += preg_match('/user\s*\(/i',  $val);						// avoid to use function user() that return current database login
		$inj += preg_match('/information_schema/i',  $val);				// avoid to use request that read information_schema database
	if ($type == 3)
		$inj += preg_match('/select|update|delete|replace|group\s+by|concat|count|from/i',	 $val);
	}
	if ($type != 2)	// Not common key strings, so we can check them both on GET and POST
	{
		$inj += preg_match('/updatexml\(/i', 	 $val);
            $object->customcode              = GETPOST('customcode','alpha');
            $object->country_id              = GETPOST('country_id','int');
            $object->finished           	 = GETPOST('finished','alpha');
            $object->fk_unit                 = GETPOST('units','alpha');
	        $accountancy_code_sell 			 = GETPOST('accountancy_code_sell','alpha');
	        $accountancy_code_sell_intra	 = GETPOST('accountancy_code_sell_intra','alpha');
	        $accountancy_code_sell_export	 = GETPOST('accountancy_code_sell_export','alpha');
	        $accountancy_code_buy 			 = GETPOST('accountancy_code_buy','alpha');
                $object->customcode             = GETPOST('customcode','alpha');
                $object->country_id             = GETPOST('country_id','int');
                $object->status                 = GETPOST('statut','int');
                $object->status_buy             = GETPOST('statut_buy','int');
                $object->status_batch	        = GETPOST('status_batch','aZ09');
                $object->finished               = GETPOST('finished','alpha');
    	        $accountancy_code_sell 			 = GETPOST('accountancy_code_sell','alpha');
    	        $accountancy_code_sell_intra	 = GETPOST('accountancy_code_sell_intra','alpha');
    	        $accountancy_code_sell_export	 = GETPOST('accountancy_code_sell_export','alpha');
    	        $accountancy_code_buy 			 = GETPOST('accountancy_code_buy','alpha');
			if ($conf->productbatch->enabled)
            if (! empty($conf->productbatch->enabled))
	if (! is_object($form)) $form = new Form($db);