upload-labs靶场通关详解:第20关 /.绕过
一、分析源代码
// 初始化上传状态标记,默认为false,即文件未上传
$is_upload = false;
// 初始化消息变量,用于存储错误信息
$msg = null;// 检查是否通过POST方式提交了表单(点击上传按钮)
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");// 从表单获取用户指定的保存文件名$file_name = $_POST['save_name'];// 提取文件扩展名(用于类型验证)$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);// 检查文件扩展名是否不在禁止列表中if(!in_array($file_ext,$deny_ext)) {// 获取上传文件的临时存储路径$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 = '禁止保存为该类型文件!';}} else {// 上传目录不存在时的错误消息$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}
}
简单概括就是,用户上传一个文件并指定保存文件的名称,再从保存文件的名称中提取扩展名进行类型验证,通过验证则移动目录。
二、解题思路
这关代码中两个重要的函数是pathinfo()函数和move_uploaded_file()函数。
pathinfo()是PHP内置函数,作用是提取文件的目录名,扩展名,文件名等部分,这一关是提取扩展名,而扩展名是通过提取文件名最后一个点(.)之后的部分。
move_uploaded_file()函数的作用是移动文件路径,在处理过程中,会自动解析并移除相对路径符号(如 /.、/..),将路径转换为绝对路径形式。
再看本关判断流程,pathinfo()函数提取扩展名验证通过后,交给move_uploaded_file()函数转移路径。
假设攻击者将文件名修改为xx.php/.这种形式,pathinfo()函数提取最后一个点(.)之后的部分为空,则绕过了黑名单的验证,转交下一步处理,而move_uploaded_file()函数又会将“/.”当作相对路径移除,最后文件就保存为了xx.php。
另外,这里的代码只有黑名单验证,用大小写,空格,点号也可以绕过上传,参考6-9关。
三、解题步骤
1.上传木马,bp抓包,将保存名称改为“xx.php/.”。
2.文件成功绕过上传,被保存为xx.php。