
XSS مخزّن عبر User-Agent في عرض الطلبات في لوحة إدارة PhocaCart
PhocaCart ≤ 6.1.7 — مهاجم غير مصادَق يخزّن حمولة XSS عبر عملية الدفع. وتُستهدف بيئة متصفح المسؤول
يخزّن PhocaCart 6.1.7 لنظام Joomla ترويسة HTTP User-Agent الخام الواردة من طلبات الدفع في جدول قاعدة بيانات الطلبات عندما يكون خيار الإعداد store_user_agent مفعّلًا. تُعرض القيمة المخزنة لاحقًا دون ترميز HTML في عرض تحرير الطلب الخاص بالمسؤول عبر itemText() الموجودة في Adminview.php.
يمكن لمهاجم غير مصادَق أن يقدّم طلبًا يحمل User-Agent معدًا يحتوي على حمولة JavaScript. وعندما يفتح المسؤول الطلب في الواجهة الخلفية، تُنفَّذ الحمولة في سياق متصفح المسؤول — ما يتيح اختطاف الجلسة أو سرقة بيانات الاعتماد أو تنفيذ إجراءات إدارية غير مصرّح بها.
تتطلب الثغرة تفعيل store_user_agent = 1 (وهي قيمة غير افتراضية). ولأن هذا الخيار قرار إداري متعمّد لجمع إحصائيات المتصفح، فإن المتاجر المتأثرة هي تلك التي فعّل فيها مالك المتجر الميزة — ما يجعل الاستغلال صامتًا تمامًا من منظور المهاجم.
| COMPONENT | VULNERABLE | TESTED ON | FIXED |
|---|---|---|---|
| PhocaCart (com_phocacart) | 5.0.0 – 6.1.7 | Joomla 5.4.7 + PhocaCart 6.1.7 + MariaDB 10.6 | 6.1.8 |
النوع: XSS مخزنة (CWE-79) — تستهدف المسؤول
المصادقة المطلوبة: لا شيء للحقن. المسؤول للتفعيل
رمز CSRF مطلوب: نعم (رمز Joomla CSRF القياسي مطلوب لعملية الدفع)
الملف: administrator/components/com_phocacart/libraries/Phoca/Render/Adminview.php:382
عند تعيين store_user_agent = 1، تعيد الدالة PhocacartUtils::getUserAgent() قيمة $_SERVER['HTTP_USER_AGENT'] دون أي تعقيم. تُخزَّن هذه السلسلة الخام في #__phocacart_orders (تُقتطع عند 200 حرف — وهو عدد غير كافٍ لمنع XSS). وعندما يعرض المسؤول الطلب في الواجهة الخلفية، تدمج itemText() القيمة المخزنة مباشرةً في استجابة HTML دون استدعاء htmlspecialchars().
مسار البيانات:
Attacker sends checkout request:
User-Agent: <script>alert(document.domain)</script>
utils.php:334 PhocacartUtils::getUserAgent()
└─ return (string) $_SERVER['HTTP_USER_AGENT'] // raw, no sanitization
order.php:413 $d['user_agent'] = substr($user_agent, 0, 200)
└─ INSERT INTO #__phocacart_orders (user_agent) VALUES ('<script>...</script>')
Admin opens order in backend:
edit.php:84 echo $r->itemText($this->itemcommon->user_agent, ...)
Adminview.php:382 '<div class="controls >' . $item . '</div>'
// → NO htmlspecialchars()
→ Browser renders: <div><script>alert(document.domain)</script></div>
→ XSS fires in administrator's browser
ORDER.PHP — مرحلة التخزين (المصدر الهش)
administrator/components/com_phocacart/libraries/phocacart/order/order.php:424
$user_agent = PhocacartUtils::getUserAgent(); // reads $_SERVER['HTTP_USER_AGENT'] raw
$d['user_agent'] = substr($user_agent, 0, 200); // stored in DB unfiltered
ADMINVIEW.PHP:382 — مرحلة العرض (نقطة التصريف الهشة)
// No htmlspecialchars() applied:
$output .= ' <div class="controls ' . $class . '">' . $item . '</div>' . "\n";
تُستدعى من administrator/components/com_phocacart/views/phocacartorder/tmpl/edit.php:84:
echo $r->itemText($this->itemcommon->user_agent, Text::_('COM_PHOCACART_USER_AGENT'), '', 'user_agent');
تمرّر الدالة itemText() قيمة $item (قيمة user_agent المخزنة) مباشرةً إلى مخرجات HTML دون أي ترميز، ما يجعلها نقطة التصريف الأساسية. وإصلاحها على مستوى نقطة التصريف يحمي جميع مستدعي itemText().
يتطلب الهجوم إكمال عملية دفع كاملة مع ترويسة User-Agent خبيثة. يجب الحصول على رمز CSRF أولًا لأن وحدة التحكم في الدفع في Joomla تتحقق من صحته.
في لوحة إدارة Joomla، انتقل إلى Components → Phoca Cart → Options → التبويب Main → Statistics Options. اضبط Store User Agent Information = Yes واحفظ.

يزور المهاجم الواجهة الأمامية للمتجر لاستخراج رمز Joomla CSRF صالح تتطلبه وحدة التحكم في الدفع. يظهر الرمز في مصدر HTML أو في إعدادات JavaScript لأي صفحة من صفحات المتجر.

يضيف المهاجم منتجًا إلى السلة عبر نقطة نهاية الدفع AJAX باستخدام User-Agent غير ضار. يؤدي هذا إلى انتقال جلسة الدفع إلى الحالة التالية.

يُرسل المهاجم معلومات الفوترة للتقدم في آلة حالات الدفع.

يختار المهاجم طريقة شحن للمتابعة إلى الدفع.

يختار المهاجم طريقة دفع (مثل: الدفع عند الاستلام).

خطوة الحقن الحاسمة. يقدّم المهاجم الطلب النهائي عبر task=checkout.order مع ضبط ترويسة User-Agent على حمولة XSS. تقرأ مهمة checkout.order قيمة HTTP_USER_AGENT الخام وتخزّنها دون تهريب في #__phocacart_orders.user_agent.
POST /index.php/shop/checkout HTTP/1.1
Host: TARGET
User-Agent: <script>alert(document.domain)</script>
Content-Type: application/x-www-form-urlencoded
phcheckouttac=1&task=checkout.order&option=com_phocacart&return=&<CSRF_TOKEN>=1
النتيجة: تم إنشاء الطلب. تخزّن قاعدة البيانات user_agent = '<script>alert(document.domain)</script>'.

ينتقل المسؤول إلى Components → Phoca Cart → Orders. يظهر الطلب المحقون في القائمة. لم يتم تفعيل XSS بعد في هذه المرحلة.

عندما ينقر المسؤول على الطلب لفتح عرض التحرير، تُعرض قيمة user_agent المخزنة دون تهريب عبر itemText(). يتم تنفيذ JavaScript فورًا.
عنوان URL المُشغِّل:
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
