目錄
一、點繞過原理
二、deldot()函數
三、源碼分析
四、滲透實戰
1、構建腳本test8.php
?2、打開靶場
3、bp開啟攔截
4、點擊上傳
5、bp攔截
6、后綴名增加點
7、發包并獲取腳本地址
8、訪問腳本
本文通過《upload-labs靶場通關筆記系列》來進行upload-labs靶場的滲透實戰,本文講解upload-labs靶場第8關文件點繞過滲透實戰。
一、點繞過原理
"點繞過"是文件上傳攻擊中一種常見的繞過技術,攻擊者通過在文件名中特殊位置插入點(.)來繞過服務器的安全校驗機制。以下是詳細的原理分析:
由于Windows系統有如下特點:
-
自動去除文件名末尾的點:“test8.php.”?→ “test8.php”
-
自動去除空格:“test8.php ”→ “test8.php”
-
忽略大小寫:“test.PHP” → “test.php”
正是因為如上第一個特點,可以構建如下攻擊流程
-
攻擊者上傳類似的文件“test8.php.”
-
由于某些系統(如Windows)會自動去除末尾的點,最終存儲為 “test.php”
二、deldot()函數
deldot() 是一個用于處理文件上傳安全的自定義函數,主要功能是刪除文件名末尾的點(.),防止攻擊者利用文件命名規則繞過安全檢測。它的作用是從字符串尾部開始,從后向前刪除點(.) ,直到末尾字符不是點為止。比如文件名 test...php 經該函數處理后可能變為 test.php 。
在upload-labs靶場中,deldot()是一個自定義的函數,在common.h中,具體如下所示。
?接下來對這段代碼進行詳細注釋,具體如下所示。
<?php
/*** 此函數用于去除字符串末尾連續的點(.)* 如果字符串末尾沒有連續的點,則直接返回原字符串* * @param string $s 要處理的字符串* @return string 處理后的字符串*/
function deldot($s) {// 從字符串的最后一個字符開始遍歷,通過 strlen($s) - 1 獲取最后一個字符的索引for ($i = strlen($s) - 1; $i > 0; $i--) {// 使用 substr 函數截取字符串中索引為 $i 的單個字符,存儲到變量 $c 中$c = substr($s, $i, 1);// 檢查當前字符是否是字符串的最后一個字符,并且這個字符不是點(.)if ($i == strlen($s) - 1 && $c != '.') {// 如果滿足條件,說明字符串末尾沒有連續的點,直接返回原字符串return $s;}// 檢查當前字符是否不是點(.)if ($c != '.') {// 如果當前字符不是點,使用 substr 函數截取從字符串開頭到當前字符(包含當前字符)的子字符串并返回return substr($s, 0, $i + 1);}}// 如果函數執行到這里,說明整個字符串可能都是點或者循環結束都沒有找到非點字符return $s;
}
?>
三、源碼分析
接下來對upload-labs 第8 關的源碼進行審計,很明顯這一關卡又是黑名單過濾,與第6關卡一樣,相對于第四關和第五關,將“.htacess和.ini”后綴均過濾了,故而無法用第四關和第五關的方法進行滲透。然而相對于第六關卡和第七關卡,缺少了一個deldot函數的處理。經過詳細注釋的代碼如下所示。
<?php
// 初始化文件上傳狀態標志,默認設置為 false,表示文件未成功上傳
$is_upload = false;
// 初始化消息變量,用于存儲上傳過程中產生的提示信息,初始值為 null
$msg = null;// 檢查是否通過 POST 方式提交了名為 'submit' 的表單元素
// 當用戶點擊提交按鈕時,會觸發此邏輯
if (isset($_POST['submit'])) {// 檢查常量 UPLOAD_PATH 所代表的上傳目錄是否存在// 只有上傳目錄存在,才能進行文件上傳操作if (file_exists(UPLOAD_PATH)) {// 定義一個數組,包含所有不允許上傳的文件擴展名// 這里涵蓋了常見的腳本文件擴展名(如 PHP、JSP、ASP 等)、網頁文件擴展名(如 HTML、HTM)以及一些特殊配置文件擴展名(如 .htaccess、.ini)$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");// 從 $_FILES 超全局數組中獲取上傳文件的原始文件名,并去除文件名首尾的空白字符$file_name = trim($_FILES['upload_file']['name']);// 使用 strrchr 函數從文件名中提取文件擴展名// strrchr 會返回從最后一個點(.)開始到字符串末尾的部分$file_ext = strrchr($file_name, '.');// 將提取的文件擴展名轉換為小寫// 這樣做是為了實現大小寫不敏感的擴展名檢查$file_ext = strtolower($file_ext); // 去除文件擴展名中可能包含的 '::$DATA' 字符串// 在 Windows 系統中,'::$DATA' 是一種特殊的文件流標識,攻擊者可能會利用它來繞過文件類型檢查$file_ext = str_ireplace('::$DATA', '', $file_ext);// 再次去除文件擴展名首尾的空白字符$file_ext = trim($file_ext); // 檢查提取并處理后的文件擴展名是否不在禁止上傳的擴展名數組中if (!in_array($file_ext, $deny_ext)) {// 從 $_FILES 超全局數組中獲取上傳文件在服務器臨時存儲的路徑$temp_file = $_FILES['upload_file']['tmp_name'];// 拼接上傳文件的最終存儲路徑// 將上傳目錄(UPLOAD_PATH)和文件名組合成完整的路徑$img_path = UPLOAD_PATH.'/'.$file_name;// 使用 move_uploaded_file 函數將臨時存儲的文件移動到指定的上傳路徑// 此函數確保文件是通過 HTTP POST 上傳的,防止惡意文件上傳if (move_uploaded_file($temp_file, $img_path)) {// 如果文件移動成功,將文件上傳狀態標志設置為 true,表示文件上傳成功$is_upload = true;} else {// 如果文件移動失敗,將錯誤信息存儲到 $msg 變量中$msg = '上傳出錯!';}} else {// 如果文件擴展名在禁止上傳的數組中,將錯誤信息存儲到 $msg 變量中$msg = '此文件類型不允許上傳!';}} else {// 如果上傳目錄不存在,將錯誤信息存儲到 $msg 變量中,并提示用戶手工創建該目錄$msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';}
}
?>
從上圖可知,源碼中沒有$file_name = deldot($file_ext);服務器無法實現將文件后的.過濾,所以可以在文件末尾添加一個“.”,這樣就可以繞過黑名單的限制
例如:上傳"test.php"文件,抓包后在文件名后添加一個點變為"test8.php.",上傳到服務器的時候,得到的后綴就是"test8.php.",從而繞過黑名單的限制。當"test8.php."文件上傳到windows服務器后,會被windows系統自動去掉不符合規則符號后面的內容(也就是將".php."中最尾部的點去掉),文件末尾就變回了".php", 這樣文件名又恢復成為"test.php",可以成功滲透。
四、滲透實戰
1、構建腳本test8.php
<?php
phpinfo();
?>
?2、打開靶場
?打開靶場第8關,瀏覽選擇該腳本,但不點擊上傳。
3、bp開啟攔截
4、點擊上傳
5、bp攔截
bp捕獲到上傳報文,下圖紅框的部分即為需要修改的文件名,需要將".php"后綴改為".php.",修改之前文件名為”test8.php“,如下所示
6、后綴名增加點
test8.php后添加一個點,變為“test8.php.”,修改后效果如下所示。
7、發包并獲取腳本地址
將bp的inception設置為off,此時修改后的報文發送成功。
回到靶場的Pass08關卡,圖片已經上傳成功,在圖片處右鍵復制圖片地址。
右鍵圖片獲取圖片地址,如下所示獲取到圖片URL。
http://127.0.0.1/upload-labs/upload/test8.php.
8、訪問腳本
?如下所示訪問test8.php腳本獲取到服務器的php信息,證明文件上傳成功。