
Ejecución remota de código autenticada en VTiger Open Source CRM v7.5
Ejecución remota de código autenticada en VTiger Open Source CRM v7.5
Existe una vulnerabilidad en el módulo Users de la versión actual de VTiger CRM Open Source 7.5.0 que permite a un atacante autenticado escribir y ejecutar código PHP arbitrario en config.inc.php.
Cuando un usuario se autentica normalmente en VTiger, se verifica su estado de configuración para determinar si es un usuario nuevo que aún no está completamente configurado. También se verifica si es el primer usuario, es decir, un administrador que debe configurar ciertas propiedades globales. En caso afirmativo, se redirige a una acción UserSetup en el módulo Users.
$userSetupStatus = Users_CRMSetup::getUserSetupStatus($focus->id);
if ($userSetupStatus) {
$user = $focus->retrieve_entity_info($focus->id, 'Users');
$isFirstUser = Users_CRMSetup::isFirstUser($user);
if($isFirstUser) {
header('Location: index.php?module=Users&action=UserSetup');
}
/modules/Users/Authenticate.php, línea 112
En esta acción se verifica si el usuario ha pasado una configuración de moneda global ("USA, Dollars" por defecto) y la guarda usando la función updateBaseCurrency.
//Handling the System Setup
$currencyName = $request->get('currency_name');
if(!empty($currencyName)) $userModuleModel->updateBaseCurrency($currencyName);
$userModuleModel->insertEntryIntoCRMSetup($userRecordModel->getId());
//End
/modules/Users/actions/UserSetupSave.php, línea 28
En la función updateBaseCurrency, el valor proporcionado se establece como la configuración de moneda global para todo el sistema en la base de datos y también llama a la función updateConfigFile, que abre el archivo de configuración y usa PHP str_replace para reemplazar el valor existente con el proporcionado.
public function updateConfigFile($currencyName) {
$currencyName = '$currency_name = \''.$currencyName.'\'';
//Updating in config inc file
$filename = 'config.inc.php';
if (file_exists($filename)) {
$contents = file_get_contents($filename);
$currentBaseCurrenyName = $this->getBaseCurrencyName();
$contents = str_replace('$currency_name =
\''.$currentBaseCurrenyName.'\'', $currencyName, $contents);
file_put_contents($filename, $contents);
}
}
/modules/Users/models/Module.php, línea 148
La acción de configuración de usuario en la versión actual de VTiger CRM no verifica si el usuario está realmente configurado o si tiene permiso para cambiar variables globales. Simplemente asume que si se accede a esa página, entonces eres la persona que debería estar configurándola. Por lo tanto, usando una cookie de sesión existente y un token CSRF tomado de cualquier carga de página autenticada, un usuario malicioso puede enviar un valor de moneda como:
USA, Dollars';@passthru($_GET['cmd']);//
Este valor se escribe ciegamente en el archivo config.inc.php como:
//Master currency name
$currency_name = 'USA, Dollars';@passthru($_GET['cmd']);//';
Dado que el archivo de configuración se carga en cada página, un usuario malicioso puede pasar simplemente un comando Unix como parámetro cmd y ver la salida en la parte superior de la página.

Este problema se solucionó en este commit donde se agregó validación adicional para asegurar que los usuarios no pudieran ingresar nombres de moneda maliciosos, y en su lugar el valor se obtendría de la tabla de la base de datos.
public function updateBaseCurrency($currencyName) {
$db = PearDatabase::getInstance();
$result = $db->pquery('SELECT currency_code, currency_symbol, currency_name FROM vtiger_currencies WHERE currency_name = ?', array($currencyName));
$num_rows = $db->num_rows($result);
if ($num_rows > 0) {
$currency_code = decode_html($db->query_result($result, 0, 'currency_code'));
$currency_symbol = decode_html($db->query_result($result, 0,'currency_symbol'));
$currencyName = decode_html($db->query_result($result, 0, 'currency_name')); // rewrite actual from table.
} else {
// Invalid currency name.
return;
}
$this->updateConfigFile($currencyName);
//Updating Database
$query = 'UPDATE vtiger_currency_info SET currency_name = ?, currency_code = ?, currency_symbol = ? WHERE id = ?';
$params = array($currencyName, $currency_code, $currency_symbol, '1');
$db->pquery($query, $params);
}