SuperAPI AI Directory

php-file-write-audit

Security & auditing

View repository

Updated 10-15 10:41

About this skill

PHP Arbitrary File Write Audit (php-file-write-audit)

Analyze the implementation logic of "writing data to disk files" in PHP project source code, focusing on:

  • Arbitrary destination write: the write target path can be controlled by an attacker (including path traversal to the destination)
  • Controllable write content: the content of the written file originates from user input (creating conditions for subsequent RCE/overwrite)
  • Overwrite/truncate mode: whether it writes in w/x and other overwrite modes, or produces an exploitable same-name conflict overwrite

Severity grading and numbering

  • See:shared/SEVERITY_RATING.md
  • Vulnerability number:{C/H/M/L}-WRITE-{序号}

WRITE Sink (required)

Identify and trace the following write/destination-change related functions/statements (selected according to what actually appears in the project):

  • Direct write:
    • file_put_contents({path}, {data})
    • fwrite($handle, {data})(usually combined with fopen($path, 'w'|'ab'|'x'|...))
    • stream_write($stream, {data}) / fputs($handle, {data})
  • Open and write (overwrite/truncate):
    • fopen($path, 'w'|'x'|'a'|'ab'|'wb'|...)
    • ftruncate($handle, {size})(if the path is controlled by the user or related to a path concatenation chain)
  • Destination changes caused by rename/copy (can form a "write destination"):
    • rename($src, $dest)
    • copy($src, $dest)
    • move_uploaded_file($tmp, $dest)(if it is not a pure UPLOAD scenario, and the core risk is a controllable destination/path)
  • Log destination writes (optional, but enable according to your project risk):
    • error_log($message, 3, $destination)(when message_type=3, destination is a file)

Path traversal to write destination detection (required)

Must analyze and provide evidence-based judgment (cannot just write "possibly"):

  1. Path concatenation and normalization chain
  • How the base directory (such as $baseDir / $uploadDir / $dataDir) is joined with user input ($base.$user / sprintf / join / array path field concatenation)
  • Whether directory sanitization/rejection of traversal fragments is performed (../、..\\, mixed separators, Windows drive letters, absolute paths, trailing whitespace, etc.)
  • Whether realpath/canonicalize is used, as well as prefix validation of "whether the final resolved path is still under the base prefix"
  1. Final resolution result of the write destination
  • Whether the target path string before writing will change the final destination due to wrapper/symlink/realpath resolution
  • Whether the final resolved target escapes the base constraint (if it escapes, the destination tends to be controllable)

Write content controllability and overwrite strategy (required)

Must trace and output (write out the chain step by step):

  1. Write content source
  • {data}/{content} Whether the parameter comes from user-controllable input (GET/POST/JSON/COOKIE/upload fields, etc.)
  • Whether it remains controllable after decode/concatenation/templating/encoding steps
  1. Overwrite/truncate mode
  • Whether the write mode is overwrite (fopen(...,'w'|'x') , etc.) or explicitly allows overwriting files with the same name
  • Whether there are mode-based conditional branches (some branches overwrite, some branches only append, etc.)

Post-write executability/reachability assessment (required)

Because file writes often directly lead to RCE, this skill must output an evidence-based judgment of "whether it can be executed/accessed after being written" (omission prohibited):

  • If what is written is a PHP/executable script: check the extension/resolution path (such as the final destination ending with .php , or the written content being included/parsed)
  • If the landing point is located in the Web root directory or an application-includable directory: output static mapping evidence (e.g., dest points to public/、www/ or a framework template/configuration directory)
  • If an "execution disabled policy" exists (e.g., the directory does not execute PHP, or the server-side configuration prohibits execution): output the corresponding evidence and the missing hint

tracer evidence references (mandatory: from php-route-tracer)

Each suspected WRITE vulnerability must item-by-item reference from the trace output ## 9) Sink Evidence Type Checklist of WRITE lineCorresponding evidence points (the status is allowed to be pending verification, but the evidence references must exist):

  1. EVID_WRITE_WRITE_CALLSITE: Evidence of the call site location for the write/landing point change (file_put_contents/fwrite/fopen('w')/rename/copy, etc.)
  2. EVID_WRITE_DESTPATH_JOIN_AND_NORMALIZATION: Evidence of destination path concatenation and normalization (base join, sanitization/rejection of traversal segments, realpath prefix validation, etc.)
  3. EVID_WRITE_DESTPATH_RESOLVED_TARGET: Evidence of the final resolved target (whether it escapes the base)
  4. EVID_WRITE_CONTENT_SOURCE_INTO_WRITE: Evidence of the mapping between the write content parameters and user-controllable input
  5. EVID_WRITE_TRUNCATE_OR_OVERWRITE_MODE: Evidence of overwrite/truncate/append modes (write mode or overwrite policy)
  6. EVID_WRITE_EXECUTION_ACCESSIBILITY_PROOF: Evidence of executability/reachability after writing (web root/includable directory/execution disabled policy, etc.)

Handling of missing tracer evidence (mandatory)

  • If in the trace's ## 9) Sink Evidence Type Checklist(WRITE line), any key evidence point is missing or cannot be mapped to this vulnerability: the status of this vulnerability can only be marked as ⚠️待验证(must not directly give ✅已确认可利用)。

tracer trigger conditions (required)

At least one of the following must be satisfied, and trace verification of the sink's existence must be relied upon:

  • The write target path reaches the write function after being passed through multiple layers of functions/object properties/JSON fields
  • The write content (data/content) remains controllable after decode/concatenation
  • There is branch logic that causes overwrite/truncation/landing in a writable and controllable directory only in some cases

Report output

Output to:

{output_path}/vuln_audit/write_{timestamp}.md

Vulnerability entry template (mandatory)

Each vulnerability must follow the structure below (must not be omitted):

### [{等级前缀}-WRITE-{序号}] 任意文件写入(路径穿越到落点/写入链)风险

| 项目 | 信息 |
|------|------|
| 严重等级 | {🔴/🟠/🟡/🔵} (CVSS {score}) |
| 可达性 (R) | {0-3} - {理由} |
| 影响范围 (I) | {0-3} - {理由} |
| 利用复杂度 (C) | {0-3} - {理由} |
| 可利用性 | ✅ 已确认 / ⚠️ 待验证 / ❌ 不可利用 / 🔍 环境依赖 |
| 位置 | {file}:{line} ({Function/Class}) |

#### 数据流链(Source -> Path Transform -> Content Transform -> Sink)
(逐行写出:用户输入进入 destination/path 的链路、归一化/净化/realpath 约束检查 -> 最终 resolved target -> 用户输入进入写入内容 data 的链路 -> 进入写入函数参数位置 -> 是否覆盖/截断 -> 写入调用点)

#### 可利用前置条件
- 鉴权要求:{无需/需登录/需特定权限}
- 输入可控性:{完全可控/条件可控/不可控}
- 触发条件:{分支/异常路径/需要特定服务器文件权限/需要落到可执行目录}

#### 证据引用(强制:来自 php-route-tracer)
必须逐项引用:
- `EVID_WRITE_WRITE_CALLSITE`:{证据点简述(包括 file:line)}
- `EVID_WRITE_DESTPATH_JOIN_AND_NORMALIZATION`:{证据点简述}
- `EVID_WRITE_DESTPATH_RESOLVED_TARGET`:{证据点简述}
- `EVID_WRITE_CONTENT_SOURCE_INTO_WRITE`:{证据点简述}
- `EVID_WRITE_TRUNCATE_OR_OVERWRITE_MODE`:{证据点简述}
- `EVID_WRITE_EXECUTION_ACCESSIBILITY_PROOF`:{证据点简述}

#### 验证 PoC(强制:可执行或可观测验证框架)
```http
{HTTP Method} {真实路由与完整参数} HTTP/1.1
Host: {host}
{必要 Header/Session/JWT/Cookie}

{Payload}

PoC output/observation points (must be clearly stated):

  • Whether the written target file appears in a Web-accessible location (or whether it can be included/read by subsequent business logic)
  • If what is written is PHP: observe whether code execution can be triggered (or at least observe file content echoing/download success)

Recommended fix

  • Based on whether the final resolved target is within the allowed base directory, enforce realpath + 前缀校验
  • Strictly restrict writable directories (allowlist), and avoid directly concatenating user input into file paths
  • Apply type constraints to written content: prohibit writing executable scripts to executable directories; make the content non-executable (e.g., only allow serialized data formats)
  • In the overwrite policy, avoid using 'w'/'x' to directly overwrite sensitive files; safely reject conflicts with the same name
  • Provide code search statements (rg): locate all write APIs and path join points

## PoC/修复建议搜索语句(强制提供参考)
- 写入 API:
  - `rg -n "file_put_contents\\(|fwrite\\(|fopen\\(|stream_write\\(|rename\\(|copy\\(|ftruncate\\(|error_log\\(" .`
- 路径拼接/归一化(常见变量名仅作提示,最终以项目为准):
  - `rg -n "realpath\\(|canonicalize\\(|\\.\\.\\/|\\.\\.\\\\|allowlist|baseDir|dest(path)?|target(path)?|mkdir\\(" .`