一、文件上传思路
首先我们通过一个网站上传一个非法格式的文件
- 在浏览加载文件,但还未点击上传按钮时便弹出对话框,内容如:只允许上传.jpg/.jpeg/.png后缀名的文件,而此时并没有发送数据包。
- 如果网页未弹窗,而在页面弹窗,则考虑后端验证
所以就围绕前端验证绕过和后端验证绕过这两方面展开讨论
二、前端验证
JavaScript验证的几种绕过方式:
- 2.1 通过浏览器审查元素对网页的代码查看,找到对文件格式或大小的限制然后修改即可;
- 2.2 通过Burpsuite工具对浏览器进行代理,抓包对包里的内容进行修改。
- 2.3最简单粗暴的就是直接浏览器禁用JavaScript脚本
三、后端验证
在学后端验证的时候先简单了解一下php中关于文件的函数
文件操作函数
-
打开文件函数fopen()
语法:fopen(文件名,文件打开方式);
返回值:若打开成功则返回文件,若打开失败则返回false
-
返回打开文件信息函数fstat()
格式:fstat(文件名);
-
关闭文件函数fclose()
格式:fclose(文件名);
返回值:成功则返回 true,如果失败则返回false。 -
读文件函数fread()
格式:fread(a,b);
a为文件系统指针,b为读取的最大字节数
返回值:成功则返回读取的内容,失败返回false
示例:读取指定长度的文件
<?php
$file=fopen("1.txt","r");//此时的$file为文件系统指针
$contents = fread($file,"10");//读取10字节的内容
fclose($file);
?>
示例:读取整个文件
<?php
$file = fopen("test.txt","r");
$contents = fread($file,filesize("test.txt"));//filesize()函数返回指定文件的大小(字节)
fclose($file);
?>
- 关于全局数组$_FILE
通过使用 PHP 的全局数组 $_FILES,你可以从客户计算机向远程服务器上传文件。
第一个参数是表单的 input name,第二个下标可以是 “name”, “type”, “size”, “tmp_name” 或 “error”。就像这样:
$_FILES[“file”][“name”] - 被上传文件的名称
$_FILES[“file”][“type”] - 被上传文件的类型
$_FILES[“file”][“size”] - 被上传文件的大小,以字节计
$_FILES[“file”][“tmp_name”] - 存储在服务器的文件的临时副本的名称
$_FILES[“file”][“error”] - 由文件上传导致的错误代码
提交表单的具体结构如下图所示:我们主要关注中间的处理程序,分析其对文件的限制
upload.php
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<form action="uploadprocess.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
uploadprocess.php
<?php
// 允许上传的图片后缀
$allowedExts = array("gif", "jpeg", "jpg", "png");//定义一个允许用户上传文件的后缀的数组
$temp = explode(".", $_FILES["file"]["name"]);explode函数的作用就算将第二个参数的文件名通过第一个参数为标准将其分割为多个数组
$extension = end($temp); // 获取文件后缀名,end表示提取数组中最后一个元素。这里恰好提取到后缀
//判断MIME类型
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
//对文件大小进行限制
&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb
&& in_array($extension, $allowedExts))//in_array函数的作用是查看第二个数组中是否存在第一个参数内容
{
if ($_FILES["file"]["error"] > 0)
{
echo "错误:: " . $_FILES["file"]["error"] . "<br>";
}
else
{
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"];
}
}
else
{
echo "非法的文件格式";
}
?>
3.1黑名单限制与白名单限制
- 3.1.1黑名单限制
简单的来说就是我不允许哪些格式上传,其他的格式我不管。比如:不允许.php .asp格式上传,如果你上传的文件的后缀与我所规定的格式匹配则会上传失败。
可以尝试php3 、php4、php5、phptml或者利用服务器解析漏洞 - 3.1.2白名单限制
白名单就是我只允许这些格式文件上传,其他文件的格式我一律不允许。如:我只允许上传jpg、png格式的文件,假如你上传一个php格式的文件,则会上传失败。也就是说只有用户上传的文件的格式与我所规定的格式匹配才会上传成功。
显然,白名单限制要比黑名单限制更加安全
3.2绕过的思路
- 3.2.1 截断
截断的原理可以类比编程里的分号,如我们一条语句要以分号结尾,或者相当于把空字节之后的内容注释掉。具体的原理讲解可参考以下博文:
[基本实验] %00截断攻击的探索
CTF实验吧-上传绕过【0x00截断】 - 3.2.2 MIME类型修改
服务器除了对文件后缀进行判断外,还有可能对其MIME类型进行判断。MIME类型我把它简单理解为文件的后缀在服务器传输过程中的一个映射,如果有理解不对的地方欢迎指出。大致就是说,我文件为jpg或者png等等格式的,抓包查看包中的内容,文件的类型就是image/jpeg
直接在工具中进行修改然后转发就可以 - 3.2.3 大小写绕过
有些网站对文件后缀名进行限制,可以尝试大小写进行绕过,如:限制php,可以采用Php。
未完待学…
上传图片的思路:
- 判断图片是否感染(上传之后再将其下载查看里面的代码是否还在)
- 判断服务器是否解析php(如果上传的服务器为单独的图片服务器则有可能不会解析php等类型的代码)