一、分析源代碼
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");$file_name = trim($_FILES['upload_file']['name']);$file_name = str_ireplace($deny_ext,"", $file_name);$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上傳出錯!';}} else {$msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';}
}
這一關仍然是黑名單過濾,但是它的代碼和前幾關都不一樣,?它這里有一行核心代碼,就是
$file_name = str_ireplace($deny_ext,"", $file_name);
str_ireplace是 PHP 內置函數,用于執行不區分大小寫的字符串替換。
語法:str_ireplace(要查找的數組, 替換值, 輸入字符串)
這行代碼的執行邏輯就是:
1.遍歷$deny_ext數組中的每個擴展名;
2.在$file_name中查找匹配項(不區分大小寫);
3.將所有匹配的擴展名替換為空字符串(即刪除)。
典型處理示例
原始文件名 | 處理后文件名 | 說明 |
---|---|---|
shell.php | shell. | 直接移除.php 擴展名 |
shell.php.jpg | shell.jpg | 僅移除第一個擴展名 |
shell.php5 | shell. | 移除 PHP 舊版本擴展名 |
SHELL.PHP | shell. | 大小寫不敏感替換 |
.htaccess | . | 移除服務器配置文件 |
exploit.jsp.asax | exploit. | 同時移除多個危險擴展名 |
二、解題思路
現在我們知道它可以刪除黑名單中的擴展名,那么這關的代碼是否存在邏輯漏洞呢?聯想第10關結合繞過的方式,是否可以再嘗試多次繞過呢?如果我上傳文件的后綴名為pphphp,代碼從第一位字母p開始讀取,讀到2-4位的時候發現這三位字母是php,于是將它替換成空白字符(刪除),這看起來沒什么問題,代碼執行下一步,構建路徑上傳文件。但是,這里的pphphp在php被刪除后,后綴只剩下了php,然后被上傳,從而構成了文件繞過,這就是雙寫繞過。
三、解題步驟
1.上傳666.php并抓包,修改后綴為pphphp。
2.放行后顯示文件上傳成功,被保存為666.php。
3.解析測試。