1、安裝Fortify並以pikachu靶場為目標進行練習熟練使用Fortify
這是一份關於安裝 Fortify SCA (Static Code Analysis) 並利用 Pikachu 靶場(一個帶有常見Web漏洞的PHP應用)進行實戰練習的詳細指南。
通過結合 Fortify 的靜態代碼掃描能力與 Pikachu 的已知漏洞,你可以深入理解代碼審計流程,學習如何定位 SQL 注入、XSS 等安全問題。
第一部分:環境準備(Pikachu 靶場)
在進行掃描之前,我們需要先獲取被掃描的目標源碼。雖然 Fortify 是靜態掃描工具(不需要代碼運行起來),但搭建好運行環境有助於你驗證掃描出的漏洞。
- 準備 PHP 運行環境
- 推薦使用 phpStudy 或 XAMPP 等集成環境,方便快捷。確保安裝路徑中不包含中文或空格。
- 下載並安裝 phpStudy 後,啓動 Apache 和 MySQL 服務。
- 下載並部署 Pikachu
- 下載源碼:訪問 Pikachu 的 GitHub 項目地址下載源碼壓縮包。
- 解壓部署:將解壓後的文件夾(重命名為
pikachu)放置在 phpStudy 的網站根目錄(通常是WWW文件夾)下。
- 配置與初始化
- 打開
pikachu/inc/config.inc.php文件,修改數據庫連接配置。將DBPW(數據庫密碼)修改為你 phpStudy 中 MySQL 的密碼(默認為root)。 - 在瀏覽器訪問
http://127.0.0.1/pikachu/install.php,點擊頁面上的“安裝/初始化”按鈕。如果出現“連接成功”的提示,説明環境搭建完畢。
第二部分:Fortify SCA 安裝與配置
Fortify SCA 是一款商業軟件,安裝過程通常包括安裝主程序、導入許可證(License)和更新規則庫。
- 安裝主程序
- 獲取 Fortify SCA 安裝包(如 Windows 版本的
.exe文件)及fortify.license文件。 - 運行安裝程序,按照嚮導操作。在安裝過程中,系統會提示選擇
fortify.license文件路徑,請正確指向該文件。 - 組件選擇:建議安裝
Audit Workbench(圖形化審計工具)和Plugin for Eclipse/Visual Studio(如果有集成開發環境需求)。對於初學者,Audit Workbench 是必須的。
- 更新規則庫 (Rulepack)
- Fortify 依靠規則庫來識別漏洞。安裝完成後,如果機器能聯網,可以使用
fortifyupdate命令自動更新。 - 如果是離線環境,需要手動下載規則包,並解壓放置在
{Fortify安裝目錄}\Core\config\rules文件夾中。
- 配置環境變量
- 為了在命令行方便使用,將
{Fortify安裝目錄}\bin添加到系統的PATH環境變量中。 - 打開 CMD 輸入
sourceanalyzer -version,若顯示版本號則安裝成功。
第三部分:使用 Fortify SCA 掃描 Pikachu
Fortify 的掃描機制分為三個階段:清理 (Clean) -> 轉換 (Translate) -> 掃描 (Scan)。對於 PHP 這種解釋型語言,轉換過程主要是解析文件結構。
方法一:使用圖形化界面 (Audit Workbench) —— 推薦初學者
- 打開 Audit Workbench。
- 點擊 "Scan" -> "Java / JSP / PHP project"(或其他類似選項,視版本而定)。
- 在彈出的對話框中,瀏覽並選擇第一步中部署的
pikachu源碼文件夾。 - Fortify 會自動識別 PHP 文件並開始“轉換”和“掃描”。配置掃描選項時,確保啓用了所有安全規則包。
- 等待掃描完成,工具會自動生成並打開一個
.fpr(Fortify Project Report) 文件。
方法二:使用命令行 (Command Line) —— 適合進階
在 CMD 中進入 pikachu 源碼目錄,依次執行以下命令:
- 清理舊的構建信息:
sourceanalyzer -b pikachu_scan -clean
- 轉換(編譯)代碼: 此步驟將 PHP 代碼轉換為 Fortify 的中間格式。
sourceanalyzer -b pikachu_scan -Xmx2G -cp "inc/*.php" "**/*.php"
- 注:
-b pikachu_scan是給本次任務起的構建ID;-Xmx2G分配內存;"**/*.php"表示遞歸處理目錄下所有 PHP 文件。 - 執行掃描並生成報告:
sourceanalyzer -b pikachu_scan -scan -f pikachu_report.fpr
- 掃描完成後,會在當前目錄生成
pikachu_report.fpr文件。
第四部分:結果分析與實戰練習
打開生成的 .fpr 文件(使用 Audit Workbench),你將看到掃描結果。這是練習的核心部分。
- 查看問題列表
- 界面左側的 "Issues" 面板會按嚴重程度(Critical, High, Medium, Low)列出漏洞。
- Pikachu 靶場主要包含 SQL 注入、XSS、CSRF 等漏洞。重點關注 Critical 和 High 級別的 "SQL Injection" 和 "Cross-Site Scripting" 條目。
- 定位漏洞代碼 (Trace Analysis)
- 雙擊某個 "SQL Injection" 問題。
- Analysis Trace(分析追蹤) 面板會顯示數據流向:
- Source(源頭):數據進入應用的地方(例如
$_POST['id'])。 - Sink(執行點):數據被執行的地方(例如
mysqli_query($link, $query))。
- 練習目標:在 Pikachu 的源碼中,對應 Fortify 報告的行號,查看代碼是否未對用户輸入進行過濾直接拼接到了 SQL 語句中。
例如,在 Pikachu 的 vul/sqli/sqli_str.php 中,Fortify 可能會指出 $name = $_GET['name'] 直接進入了 SQL 查詢,導致注入。
- 驗證與修復(舉一反三)
- 驗證:回到瀏覽器中運行的 Pikachu 靶場,找到對應的漏洞頁面(如 SQL-Inject -> 字符型注入),嘗試利用 Fortify 指出的參數進行攻擊(輸入
' or 1=1#)。 - 修復建議:查看 Fortify 提供的 "Recommendations" 標籤,它會建議使用預編譯語句(Prepared Statements)來修復 SQL 注入。你可以嘗試修改 Pikachu 的源碼進行修復,然後重新掃描驗證漏洞是否消失。
總結
通過以上步驟,你不僅學會了 Fortify SCA 的安裝與基本使用,還通過 Pikachu 靶場 實現了“掃描-分析-驗證”的閉環學習。
- 安裝要點:確保 License 有效,規則庫是最新的。
- 掃描要點:PHP 項目可以直接掃描源碼目錄,無需複雜的編譯環境。
- 分析要點:重點利用 Analysis Trace 追蹤數據流,理解“污點分析”(Taint Analysis)原理。
2、複習php代碼審計函數精講相關內容,重點是SESSION驗證繞過、urldecode二次編碼繞過、str_replace繞過
SESSION驗證繞過
在PHP代碼審計中,SESSION驗證繞過是指攻擊者通過利用代碼邏輯缺陷、配置錯誤或特定的PHP特性,在未經過正常登錄授權的情況下,欺騙服務器認為當前請求具有合法會話權限,從而訪問後台或敏感功能。
以下是PHP代碼審計中常見的SESSION驗證繞過漏洞類型及原理解析:
1. header 重定向未終止執行(最常見)
這是PHP代碼審計中最高頻的低級邏輯錯誤。開發者在判斷用户未登錄時,使用 header("Location: ...") 跳轉到登錄頁,但忘記在 header 函數後立即終止腳本運行(如使用 exit() 或 die())。
- 漏洞原理:PHP是解釋型語言,
header函數只是向瀏覽器發送一個HTTP響應頭(通常是302跳轉),告訴瀏覽器去訪問另一個頁面。如果腳本沒有被終止,服務器會繼續執行header之後的代碼,並將剩餘頁面的HTML內容發送給客户端。 - 審計關鍵詞:搜索
header、Location:,檢查其後是否跟隨exit或die。 - 代碼示例:
// 漏洞代碼
session_start();
if (!isset($_SESSION['user'])) {
header("Location: login.php");
// 錯誤:這裏缺少 exit(); 腳本會繼續向下執行
}
// 敏感操作或後台內容
echo "歡迎管理員,這是隻有登錄後才能看到的數據...";
unlink("important_file.txt");
- 繞過方式:攻擊者使用抓包工具(如Burp Suite)或命令行工具(如curl),配置其不自動跟隨跳轉。雖然HTTP狀態碼是302,但響應包的Body部分包含了敏感數據或已經執行了敏感操作。
2. 變量覆蓋導致 SESSION 偽造
在舊版本PHP(register_globals=On)或使用了不安全的函數(如 extract()、parse_str())時,攻擊者可以通過GET/POST參數直接覆蓋 $_SESSION 變量。
- 漏洞原理:如果代碼中存在
extract($_POST)或類似的變量註冊操作,且位於session_start()之後,攻擊者可以傳入名為_SESSION[user]的參數來覆蓋服務器端的會話數據。 - 審計關注點:查找
extract()、parse_str()、$$(可變變量)的使用位置。 - 代碼示例:
session_start();
$id = $_GET['id'];
extract($_GET); // 危險:如果攻擊者傳入 ?_SESSION[admin]=1
if ($_SESSION['admin'] == 1) {
echo "管理員登錄成功";
}
3. 會話固定 (Session Fixation)
開發者在用户登錄成功後,沒有重置會話ID(session_id),導致攻擊者可以使用預先獲取的Session ID劫持用户會話。
- 漏洞原理:攻擊者生成一個合法的Session ID(例如通過訪問網站獲得),並通過URL參數誘導受害者使用該Session ID登錄。由於登錄後ID未改變,攻擊者持有的ID隨即變為已授權狀態。
- 審計關注點:檢查登錄成功的邏輯塊中,是否調用了
session_regenerate_id(true)。 - 修復方案:登錄成功後必須刷新Session ID。
4. 弱類型比較與邏輯漏洞
PHP的弱類型比較(==)可能導致驗證邏輯被繞過,特別是在SESSION值為空或布爾值判斷時。
- 漏洞原理:
- 空值繞過:如果代碼寫成
if ($_SESSION['admin'] == true),而在某些配置下未初始化的SESSION可能被視為空或null,在弱比較下可能產生非預期的結果(取決於具體邏輯,例如"" == 0為真)。 - 驗證邏輯錯誤:有時開發者會判斷COOKIE中的值來代替SESSION驗證,例如
if ($_COOKIE['is_admin']),這是完全不可信的,因為COOKIE完全由客户端控制。
- 代碼示例:
// 錯誤示例:依賴客户端COOKIE進行權限驗證
if ($_COOKIE['user_role'] == 'admin') {
// 攻擊者只需修改瀏覽器Cookie即可繞過
}
5. 結合 LFI (文件包含) 利用 Session
如果網站存在本地文件包含(LFI)漏洞,但無法上傳文件,攻擊者可以通過操縱SESSION文件來實現代碼執行(RCE),這是一種高級的利用方式。
- 漏洞原理:PHP將Session數據存儲在服務器的文件中(通常在
/tmp或/var/lib/php/sessions)。攻擊者可以通過特定的設置(如PHP_SESSION_UPLOAD_PROGRESS)向Session文件中寫入惡意代碼,然後利用LFI漏洞包含該Session文件。 - Bypass技巧:有時Session內容經過了Base64編碼或其他處理,直接包含無法解析。攻擊者可以利用
php://filter對Session文件進行解碼後再包含,從而繞過原本的編碼限制。
6. 驗證碼與Session的邏輯缺陷
在涉及驗證碼的場景中,如果Session處理不當,可能導致驗證碼驗證被繞過。
- 漏洞原理:
- 驗證碼未清除:驗證碼使用一次後未在Session中銷燬,導致攻擊者可以重複使用舊的驗證碼進行爆破。
- Session置空繞過:某些邏輯是
if ($code != $_SESSION['code']),如果攻擊者能讓Session不生成(例如刪除對應的Cookie),導致$_SESSION['code']為空,同時提交空的驗證碼,某些情況下null == null判定為真從而繞過。
總結與防禦建議
在進行代碼審計時,關於SESSION驗證應重點檢查以下幾點:
- 完整性檢查:所有權限驗證跳轉後必須緊跟
exit()或die()。 - 數據來源:永遠不要信任
$_COOKIE中的權限標識,權限驗證必須基於服務端的$_SESSION。 - 生命週期:登錄成功後強制重置 Session ID (
session_regenerate_id)。 - 嚴格比較:使用
===進行全等比較,避免弱類型問題。 - 變量安全:避免使用
extract等函數直接處理用户輸入覆蓋全局變量。
urldecode二次編碼繞過
在 PHP 代碼審計過程中,利用 urldecode() 進行二次編碼繞過是一個比較經典的繞過手法,尤其在某些包含黑名單或正則檢測的場景中,這種技術能幫助安全測試人員規避檢測邏輯,成功觸發代碼執行、獲得敏感信息或繞過安全過濾。下面我將從原理、利用條件、案例以及防禦措施幾個方面詳細解釋。
1. 原理分析
urldecode() 是 PHP 內置的 URL 解碼函數,用於將經過 URL 編碼的字符串還原成原始字符。例如:
<?php
echo urldecode("hello%20world"); // 輸出 hello world
?>
在 Web 流程中,URL 解碼的過程可能不止一次:
- 第一次解碼:瀏覽器或 Web 服務器對請求參數進行 URL 解碼。
- 第二次解碼:應用代碼中顯式調用
urldecode()再次解碼參數。
如果編碼過的字符經過兩輪解碼才能恢復原始形式,就形成了所謂的 “二次編碼繞過”。
例如:
"J"→%4A(一次 URL 編碼)%4A→%254A(將%也做一次 URL 編碼)
當服務端收到 %254A 時:
- 瀏覽器/服務器自動解碼
%25→%,得到%4A - PHP 代碼調用
urldecode()再解碼%4A→J
2. 漏洞形成原因
這種繞過在以下場景可能出現:
- 程序在 安全檢測之前 調用了
urldecode(),而檢測邏輯用的是未解碼的數據。 - 檢測邏輯只對一次解碼後的數據進行匹配,沒有考慮多層編碼的可能。
- 結合黑名單過濾,如
eregi()、preg_match()檢測某些敏感詞,攻擊者通過二次編碼改變第一次匹配結果,從而繞過。
3. 案例演示
假設存在如下 PHP 代碼(簡化版):
<?php
$id = $_GET['id'];
if (!eregi("hackerDJ", $id)) {
// 如果沒有匹配到 hackerDJ 就繼續往下執行
$id = urldecode($id);
if (eregi("hackerDJ", $id)) {
echo "get flag!";
}
}
?>
正常情況下:
?id=hackerDJ第一次檢查匹配到,不能獲得 flag。- 但如果傳入
%254A這種二次編碼,就可以繞過:
- 第一次檢查
?id=hackerD%254A不會匹配到hackerDJ urldecode()第二次解碼%4A→J,得到hackerDJ,匹配成功,從而繞過防護[1]。
Payload 示例:
?id=hackerD%254A
編碼過程:
J→%4A%→%25,最終%4A→%254A
4. 繞過優勢
- 可以對任意敏感字符或關鍵字進行分段二次編碼,使它們避開第一次檢測。
- 在一些 WAF 或安全模塊只解碼一次時,也可有效繞過。
- 對於多層編碼的輸入,正常用户功能不受影響,但攻擊者能構造特定惡意輸入。
5. 防禦措施
為了避免“二次編碼繞過”漏洞,建議:
- 統一輸入處理順序
對輸入進行解碼、過濾的順序應設計合理,不要在過濾後再解碼。 - 一次性完全解碼
對輸入進行多次解碼(直到不變)再進行安全檢查,例如:
<?php
function full_urldecode($str) {
$decoded = $str;
while(($tmp = urldecode($decoded)) !== $decoded) {
$decoded = $tmp;
}
return $decoded;
}
?>
- 使用白名單驗證
對輸入進行嚴格格式限定,不依賴黑名單。 - 避免危險函數
例如eregi()在 PHP 7 已移除,建議用preg_match()並添加u統一編碼模式。
✅ 總結:
在 PHP 代碼審計中,urldecode() 的二次編碼繞過手法本質是利用不恰當的解碼順序和安全檢測機制之間的差異。審計時要特別關注輸入的解碼次數與檢測邏輯的順序,防禦時應確保過濾和解碼的順序正確且全面。
str_replace繞過
好的,我們來系統講一下 PHP 代碼審計中 str_replace 繞過技巧——這是 Web 安全滲透和 CTF 中非常常見的一個繞過點,因為很多開發者會用 str_replace() 做黑名單過濾,但用法不當卻會被輕鬆繞過。
1. 原理簡介
str_replace($search, $replace, $subject) 會將 $subject 中所有 $search 替換為 $replace(區分大小寫)常見的過濾邏輯:
$input = $_GET['id'];
$input = str_replace("select", "", $input);
開發者希望這樣來防 SQL 注入或其他攻擊,但過濾本質只是字符串替換,並不能真正阻止複雜構造——例如攻擊者可以通過 雙寫繞過 或 編碼繞過 恢復被替換的關鍵字。
2. 常見繞過方式
(1) 雙寫繞過
str_replace("select", "", "selselectect") 執行順序:
- 第一次匹配
"select"→ 刪除
"selselectect"→"sel"+"ect"刪除後成"select" - 第二個
"select"被保留 → 實際還是"select"
這種方法在過濾敏感關鍵字時經常失效。
(2) 大小寫繞過
str_replace() 區分大小寫,因此:
str_replace("select", "", "SELECT * FROM")
不會替換掉 SELECT(大寫)。
可以手動混合大小寫,例如 SeLeCt,從而繞過過濾。
防禦方法:用 str_ireplace()(不區分大小寫的替換)。
(3) 編碼繞過
- URL 編碼:
select→%73%65%6c%65%63%74 - 會先解碼一次,如果在過濾前解碼不足或順序錯誤,可以通過二次編碼繞過(結合
urldecode()二次繞過)。
(4) 拼接繞過
例如過濾了 php://:
$page = str_replace("php://", "", $_GET['page']);
include($page);
攻擊者可以用 雙寫 或 分段拼接:
phpphp:////input→ 第一次替換刪掉一個"php://", 剩下"php://input"$a = "php:/"; $b = "/input";→ 變量拼接。
(5) 正則繞過
如果配合正則檢測和替換(不嚴謹),也可能通過特殊字符轉義或者異或字符串來繞過,例如:
$str = str_replace("flag", "", $_GET['cmd']);
用 "flflagag" 雙寫,讓替換後還能得到 "flag"。
3. 樣例漏洞
漏洞代碼:
<?php
$id = $_GET['id'];
$id = str_replace("'", "", $id);
$sql = "SELECT * FROM users WHERE id='$id'";
echo $sql;
?>
繞過方法:
請求:
?id=1' OR '1'='1
變成:
str_replace("'", "", "1' OR '1'='1") → "1 OR 1=1"
結果:
SELECT * FROM users WHERE id='1 OR 1=1'
依然是 SQL 注入。
4. 防禦建議
- 不要用
str_replace代替輸入驗證 使用參數化查詢(PDO、mysqli)才是安全防 SQL 注入的方式。 - 統一大小寫處理 如果必須替換敏感詞,先
strtolower(),然後用str_replace。 - 多輪替換 如果繼續用
str_replace,要在循環中反覆替換直到內容不變:
do {
$old = $input;
$input = str_replace("select", "", $input);
} while ($old !== $input);
- 白名單模式
限制輸入字符範圍,比如只允許數字和字母:
if (!preg_match('/^[a-zA-Z0-9]+$/', $input)) exit('invalid');
總結
在代碼審計中,遇到 str_replace 做黑名單過濾時,要立刻考慮 雙寫繞過、大小寫繞過、編碼繞過、拼接繞過 等方式。
在防禦時,應改用白名單驗證、參數化查詢以及一次性完整解碼檢測,徹底避免此類漏洞。
3、複習php偽協議
PHP 偽協議(PHP Pseudo-protocols),也稱為PHP 封裝協議(Wrappers),是 PHP 提供的一種統一、簡潔的接口,允許開發者使用標準的文件操作函數(如 fopen, copy, file_exists, include, file_get_contents 等)來處理各種不同的數據流(如本地文件、HTTP 請求、輸入輸出流、壓縮文件等)。
在 Web 安全(特別是 CTF 比賽)和高級開發中,PHP 偽協議因其能訪問特殊資源或繞過安全限制而備受關注。
以下是 PHP 偽協議的詳細解析、常用協議及其在安全領域的應用:
1. 核心配置前提:php.ini
偽協議的使用受 php.ini 配置文件中兩個參數的直接影響:
allow_url_fopen: 默認開啓 (On)。允許 PHP 訪問 URL 形式的遠程文件(如http://,ftp://)。allow_url_include: 默認關閉 (Off)。允許include,require等函數使用 URL 形式的封裝協議。注意:php://input,php://stdin,php://memory,php://temp需要此項開啓才能在文件包含函數中使用。
2. 最常用的 PHP 偽協議詳解
2.1 php://filter (數據流過濾器)
這是 Web 安全中最常利用的協議。它是一種元封裝器,設計用於在數據流打開時對數據進行篩選和過濾。
- 作用:在讀取文件內容之前,對其進行編碼或處理。
- 安全場景:任意文件讀取。當網站存在文件包含漏洞(LFI),但直接包含 PHP 文件會被服務器執行而無法看到源碼時,攻擊者利用該協議將源碼進行 Base64 編碼後輸出,從而獲取源代碼。
- 語法格式:
php://filter/read=<讀鏈過濾器>/resource=<目標文件>
- 典型 Payload:
?file=php://filter/read=convert.base64-encode/resource=index.php
- 解釋:讀取
index.php的內容,經過base64-encode過濾器處理後輸出。拿到密文後解碼即可看到 PHP 源碼。
2.2 php://input (原始輸入流)
這是一個只讀流,允許訪問請求的原始數據的只讀流。
- 作用:獲取 POST 請求中的原始數據(Raw Data)。對於處理非表單數據(如 JSON、XML)非常有用。
- 安全場景:遠程代碼執行 (RCE)。如果
allow_url_include為 On,且存在include($_GET['file'])漏洞,攻擊者可以通過 POST 發送 PHP 代碼,並讓服務端包含php://input來執行這些代碼。 - 限制:當
enctype="multipart/form-data"時,php://input無效。 - 典型 Payload:
- URL:
?file=php://input - POST Data:
<?php system('ls'); ?>
2.3 file:// (本地文件系統)
PHP 默認使用的封裝協議,用於訪問本地文件系統。
- 作用:讀取服務器本地文件。
- 語法:
file:///path/to/file.ext(必須是絕對路徑,或者在某些函數中支持相對路徑)。 - 安全場景:雖然普通的文件路徑也能包含,但顯式使用
file://協議常用於繞過某些針對特定路徑格式的過濾。
2.4 data:// (數據流封裝器)
該協議允許將數據直接作為“文件”內容傳遞給 PHP。
- 前提:
allow_url_fopen和allow_url_include均需開啓。 - 安全場景:RCE。類似於
php://input,但數據直接拼接在 URL 中。 - 典型 Payload:
?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+
- 解釋:base64 解碼後為
<?php phpinfo();?>,服務器會像讀取文件一樣讀取這段字符串並作為代碼執行。
2.5 壓縮文件協議 (zip://, bzip2://, zlib://, phar://)
這些協議用於直接訪問壓縮包內部的文件。
zip://:
- 格式:
zip://[壓縮包絕對路徑]#[壓縮包內文件名] - 場景:配合文件上傳漏洞。攻擊者上傳一個改了後綴(如
.jpg)的 ZIP 包,然後通過zip://協議包含包內的 PHP 木馬。
phar://:
- 格式:
phar://[壓縮包路徑]/[包內文件名] - 特點:類似 ZIP,但在解析 PHAR 文件元數據時會觸發反序列化,常用於反序列化漏洞利用。
3. PHP 偽協議彙總表
|
協議名稱 |
描述 |
關鍵用途/漏洞點 |
依賴配置 (include場景) |
|
file:// |
訪問本地文件系統 |
讀取敏感文件 ( |
|
|
php://filter |
篩選過濾數據流 |
任意文件讀取 (Base64編碼) |
無特殊依賴 |
|
php://input |
訪問POST原始數據 |
代碼執行 (POST PHP代碼) |
|
|
data:// |
數據流封裝 |
代碼執行 (URL中嵌入代碼) |
|
|
zip:// |
訪問ZIP文件內容 |
配合文件上傳 GetShell |
|
|
phar:// |
PHP歸檔文件 |
反序列化攻擊、文件包含 |
|
|
http:// |
訪問 HTTP(s) 網址 |
遠程文件包含 (RFI) |
|
4. 安全防禦建議
由於偽協議的強大功能,它們經常被黑客利用。防禦措施包括:
- 關閉危險配置:在
php.ini中設置allow_url_include = Off,這可以防禦php://input和data://的大部分遠程代碼執行攻擊。 - 嚴格過濾:對用户輸入的參數(如
$_GET['file'])進行白名單校驗,禁止包含php://,data://等字符串。 - 路徑限制:使用
open_basedir限制 PHP 只能訪問指定的目錄,防止通過file://讀取系統敏感文件。
4、搭建並部署微商城系統並結合Fortify審計文件上傳漏洞
具有上傳漏洞的代碼片段:
elseif($mod == "upload"){
$type = daddslashes($_REQUEST['type']);
if($type == 1){
if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/png") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 5242880)){
if ($_FILES["file"]["error"] > 0){
$result=array("code"=>-2,"msg"=>"上傳出錯!");
exit(json_encode($result));
}else{
$cmm = date("YmdHis").rand(111,999);
$name = explode('.',$_FILES["file"]["name"]);
$newPath = $cmm.'.'.$name[1];
if (preg_match("/[\x7f-\xff]/", $newPath)) {
$result=array("code"=>-3,"msg"=>"文件名稱不能為中文!");
exit(json_encode($result));
}
if (file_exists("../upload/" . $newPath)){
$result=array("code"=>-2,"msg"=>"上傳出錯!");
exit(json_encode($result));
}else{
move_uploaded_file($_FILES["file"]["tmp_name"],"../upload/" . $newPath);
$lj=array("src"=>"/upload/{$newPath}","title"=>"圖片");
$result=array("code"=>0,"msg"=>"上傳成功!","data"=>$lj,"name"=>"/upload/{$newPath}");
exit(json_encode($result));
}
}
}else{
$result=array("code"=>-3,"msg"=>"圖片大小不能超過5M!{$_FILES["file"]["size"]}");
exit(json_encode($result));
}
}
else{
$result=array("code"=>-1,"msg"=>"上傳類型不存在!");
}
exit(json_encode($result));
}//圖片上傳接口
構造php文件上傳成功之後,可以獲得文件在服務器後端的路徑,/upload/{$newPath}:
$result=array("code"=>0,"msg"=>"上傳成功!","data"=>$lj,"name"=>"/upload/{$newPath}");