前言
现代互联网的Web应用程序中,上传文件是一种常见的功能,因为它有助于提高业务效率,如企业的 OA 系统,允许用户上传图片、视频、头像和许多其他类型的文件。然而向用户提供的功能越多,Web应用受到攻击的风险就越大,如果Web应用存在文件上传漏洞,那么恶意用户就可以利用文件上传漏洞将可执行脚本程序(WebShell)上传到服务器中,获得网站的权限,然后可以进一步对服务器进行入侵,扩大控制权限。
1.提问:什么是文件上传漏洞?
文件上传就是将本地文件上传至服务器上进行保存。其漏洞产生原因是没有对上传的文件进行严格校验,那么可能会导致用户上传脚本文件,然后用户再通过访问这些文件的方式,来达到执行该脚本文件,从而控制服务器的目的。
2.提问:文件上传的业务逻辑?
当我们找到上传的入口,上传文件至服务器上进行保存,可能会回显文件上传的路径,如果回显了文件上传路径,那么我们就可以根据回显的文件上传路径进行访问,那么我们就可以在浏览器中访问到服务器上的这个文件。
3.提问:什么是一句话木马?
一段简单的代码,就相当于植入的木马。这里的php代码:<?php @eval($_POST['shell']);?> 其中shell是一个变量,用post方法获取shell属性值,eval是执行代码。即Web服务器对shell取值以后,然后通过eval()函数执行shell里面的内容。注意POST也可替换成GET,但同时shell的传递方式也要改为GET形式性。
我们在靶场练习的步骤:首先利用一些方法来把这个文件代码上传成功,然后利用一些工具进行测试连接,为shell变量提供变量值,这里的变量值就是一些命令,这样的好处就是省去我们自己敲代码的时间。
一、文件上传的验证机制有哪些?(前端校验、后端校验)
1、前端校验
前端页面在提交上传文件时,会有文件类型的校验,如果不是指定的文件类型,就拒绝提交。解决办法就是可以编辑一下页面JS,或者使用BP工具抓包修改内容就能绕过了。
(1)方法一:修改JS其中关键的检测函数
以第一关为例:
checkfile()是检测函数,我们把它删除掉即可,改成return true。(如何快速找到checkfile函数:点击左上角的方框箭头,然后点击页面的上传按钮即可。)
然后上传php文件即可成功。
右击鼠标,选择复制图像链接。
打开哥斯拉工具
(2)方法二:BP工具
客户端直接发送请求包,我们可以通过Burp抓到正常上传的请求报文后,修改报文的内容后,直接通过Burp发送到服务端,这样就可以跳过网页中JS的验证。将1.png修改成1.php,将content-type类型修改为application/x-php。
2、后端校验
黑白名单、后端检查的内容、代码逻辑
后端检查文件后缀名之黑名单黑名单限制 - 利用后端解析差异
., 空格,::$DATA
白名单
后端检查Content-Type
后端检查文件头内容
我们据此可以修改响应的内容,进行绕过上传文件。
后缀名大小写绕过
重写绕过
利用操作系统特性绕过
利用缺陷的文件上传验证
文件类型验证缺陷 - 通过不常见的后缀绕过 比如:php3,php5等等
上传目录限制文件类型 - 尝试利用目录遍历将文件上传到其他目录
后缀限制 - 通过.htaccess 欺骗服务器扩展任意自定义文件后缀到已知的MIME类型;利用.user.ini 包含jpg文件到任意已存在php文件中
利用%00绕过PHP
黑名单过滤后缀 - 通过双写绕过
文件内容检查 - 通过添加允许文件头格式绕过
通过条件竞争实现文件上传
二、upload-labs靶场练习
1、第1关(js检测绕过)
修改前端代码
2、第2关(MIME验证绕过)
(1) 源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
(2)绕过原理与方法
根据代码:
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
可以看出这里是规定了content-type的类型,所以我们上传符合格式的文件:image/png、image/gif。然后利用burp抓包,进而修改filename值(文件后缀名)即可。
利用bp抓包,将文件后缀名改为php
(3)总结
注意conten-type类型不需要修改,只需要修改filename值即可。
3、第3关(黑名单验证,特殊后缀)
(1) 源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
如果继续按照第二关做法:
会出现红色提示。这是因为对文件名后缀有了限制。
在对文件名后缀做处理:转换为小写、去除字符串、首位去空
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA