Analyze the implementation logic of "extracting/unpacking archive files to a disk directory" in PHP projects. Focus on auditing Zip Slip-type issues: an attacker can use a carefully crafted archive entry name (entry name/path) to make the final write location escape the target directory.
Grading and numbering
- See:
shared/SEVERITY_RATING.md - Vulnerability ID:
{C/H/M/L}-ARCHIVE-{序号}
ARCHIVE Sink (mandatory)
Identify and trace archive extraction call sites, including at least:
ZipArchive->extractTo($destination, {value})ZipArchive->extract($destination, {value})(if the project uses a wrapper)PharData->extractTo($destination, {value})Archive_Tar->extractTo($destination, {value})(if the project uses PEAR/equivalent wrappers)Archive_Tar->extract($destination, {value})(if the project uses a wrapper)- Custom extraction wrapper: ultimately still performs "join to the destination directory and write to disk" for each entry name
Mandatory evidence points (mandatory: trace contract alignment)
Each suspected ARCHIVE vulnerability must cite item by item php-route-tracer in the trace output, ## 9) Sink Evidence Type Checklist the ARCHIVE linecorresponding evidence points (status may be pending verification, but evidence citations must exist):
EVID_ARCHIVE_EXTRACT_CALLSITE: evidence of the archive extraction/unpacking call site (extractTo/extractTo wrapper function entry)EVID_ARCHIVE_ENTRY_NAME_SOURCE: evidence of the source of the entry name/path (from the archive content's entry list, or an entry path constructed from user input)EVID_ARCHIVE_ENTRY_SANITIZATION: evidence of entry path sanitization/normalization (removing/rejecting../, absolute paths, drive letters, and other path traversal fragments; and how encoding/homoglyph characters are handled)EVID_ARCHIVE_EXTRACT_BASE_DIR: evidence of the extraction base directory (the source and passing method of the destination/base directory)EVID_ARCHIVE_FINAL_TARGET: evidence of the final resolved write location (the resolved final path after entry join, and whether the base directory constraint determination holds)
Exploitability and vulnerability validity conditions (mandatory)
Must output and determine:
- Whether the entry name/path can be controlled by the attacker (at least from entries in the attacker's crafted zip)
- Whether the base directory constraint is actually enforced "after final path resolution" (e.g.,
realpath+ prefix validation, rather than only string replacement) - Whether bypasses exist: double encoding, mixed separators, Windows drive letters, absolute paths, trailing/whitespace/control characters, Unicode homoglyph characters, etc.
- Whether the write actually occurs outside the target directory (or at least whether it can be proven that the final target escapes)
Tracer trigger conditions (mandatory)
When any condition is met, it must rely on php-route-tracer:
- The destination/base directory or entry name enters extractTo only after multiple layers of function/object wrapping.
- There is branch logic in the entry name list or extraction path (some entries are filtered/some branches are not filtered).
Report output
Output to:
{output_path}/vuln_audit/archive_{timestamp}.md
Vulnerability entry template (mandatory)
Each vulnerability must follow the structure below (must not be omitted):
### [{等级前缀}-ARCHIVE-{序号}] 归档解压路径穿越(Zip Slip)风险
| 项目 | 信息 |
|------|------|
| 严重等级 | {🔴/🟠/🟡/🔵} (CVSS {score}) |
| 可达性 (R) | {0-3} - {理由} |
| 影响范围 (I) | {0-3} - {理由} |
| 利用复杂度 (C) | {0-3} - {理由} |
| 可利用性 | ✅ 已确认 / ⚠️ 待验证 / ❌ 不可利用 / 🔍 环境依赖 |
| 位置 | {file}:{line} ({Function/Class}) |
#### 数据流链(Source -> Transform -> Sink)
(逐行写出:归档 entry name/path 进入 -> 净化/归一化 -> base destination join -> resolved final target -> 是否逃逸 base 约束 -> 实际写入/提取调用点)
#### 可利用前置条件
- 鉴权要求:{无需/需登录/需特定权限}
- 输入可控性:{完全可控/条件可控/不可控}
- 触发条件:{分支/异常路径/需要特定归档格式/需要特定服务器文件权限}
#### 证据引用(强制:来自 php-route-tracer)
必须逐项引用:
- `EVID_ARCHIVE_EXTRACT_CALLSITE`:{证据点简述}
- `EVID_ARCHIVE_ENTRY_NAME_SOURCE`:{证据点简述}
- `EVID_ARCHIVE_ENTRY_SANITIZATION`:{证据点简述(缺失则写“未发现过滤/归一化不足”并给出 trace 证据)}
- `EVID_ARCHIVE_EXTRACT_BASE_DIR`:{证据点简述}
- `EVID_ARCHIVE_FINAL_TARGET`:{证据点简述(说明 resolved target 是否逃逸)}
#### 验证 PoC(强制:可观测验证框架)
```http
{HTTP Method} {真实路由与完整参数} HTTP/1.1
Host: {host}
{必要 Header/Session/JWT/Cookie}
{Payload}
PoC generation/trigger strategy (you must clearly state what you want to observe):
- Create a malicious archive containing a path traversal entry, e.g.,
../../../../var/www/html/pwn.php(or a Windows path variant) - Trigger the extraction route (usually after uploading an archive/or providing a downloadable URL and having the server extract it)
- Observation point: whether files appear outside the target directory and whether the landing point can be accessed (depending on site permissions/writable directory policy)
Recommended fix
- Base it on the "final resolved landing point": normalize the entry name and then perform
realpath+ base prefix validation - Disallow absolute paths/drive letters/backslash separators/directory traversal: if traversal segments are found in the entry name, reject or skip it directly
- In the archive processing workflow, uniformly sanitize the entry name list and enforce a consistent base constraint on the extraction process
- Provide code search statements:
rglocate allextractTo/extract/archive extraction wrapper entry points and destination concatenation logic
## tracer 证据缺失处理(强制)
- 若 trace 中任一关键证据点(`EVID_ARCHIVE_EXTRACT_CALLSITE / EVID_ARCHIVE_ENTRY_NAME_SOURCE / EVID_ARCHIVE_ENTRY_SANITIZATION / EVID_ARCHIVE_EXTRACT_BASE_DIR / EVID_ARCHIVE_FINAL_TARGET`)缺失或无法对应到本条漏洞:该条漏洞状态只能标记为 `⚠️待验证`,不得直接给出 `✅已确认可利用`。