目录
先补充前置知识
$_FILES
PHP 的全局数组 $_FILES,通过其我们可以向服务器上传文件。全局意味着我们可以在任何位置访问到这个变量
1. 建立一个 form.html 演示上传文件,其中的代码如下:
<html>
<head></head>
<body></body>
<form enctype="multipart/form-data" action="upload_file.php" method="POST">
<input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>
</html>
2. 新建一个用于接收文件信息的 PHP 文件 upload_file.php,代码如下:
<?php
header("content-type:text/html;charset=utf-8");
echo "<pre>"; //数组前加echo '<pre>'; 出来格式化效果
print_r($_FILES);
echo "<br>";
echo "上传的文件名:".$_FILES['userfile']['name'] //userfile,就是上传的file表单中name的值
?>
当上传一张图片后,获取的内容如下
即,当我们上传图片后,我们获得了一个$_userfile的一个数组,数组的键就是文件的一些固定属性,数组的值就是文件属性的值
$_FILES数组内容如下:
$_FILES['userfile']['name'] 客户端文件的原名称。
$_FILES['userfile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
$_FILES['userfile']['size'] 已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认,脚本执行结束后临时文件就会被删除,所以需要我们进行文件的移动
$_FILES['userfile']['error'] 和该文件上传相关的错误代码。['error'] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在PHP3.0以后成了常量)
UPLOAD_ERR_OK
值:0; 没有错误发生,文件上传成功。
UPLOAD_ERR_INI_SIZE
值:1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
UPLOAD_ERR_FORM_SIZE
值:2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
UPLOAD_ERR_PARTIAL
值:3; 文件只有部分被上传。
UPLOAD_ERR_NO_FILE
值:4; 没有文件被上传。
值:5; 上传文件大小为0.
Pass-01 - js限制
上传源码如下,功能就是将文件移动到新的地方,此进行任何的限制
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$temp_file = $_FILES['upload_file']['tmp_name']; #获取上传文件的临时文件名及路径
#UPLOAD_PATH为定义在其他文件中的超全局变量,define("UPLOAD_PATH", "../upload");
#$_FILES['upload_file']['name']为上传时的源文件名
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']; #即定义新的文件路径和文件名
if (move_uploaded_file($temp_file, $img_path)){ #将临时文件移动到新的地方
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
上传限制函数为js函数,所有的js限制都只是发生在浏览器上,并没有任何luan用,漏洞点就是发生在限制函数为js限制
方法1
1. 直接上传一个1.php的文件,内容为一句话木马
<?php phpinfo(); ?> |
我们上传的时候开启了bp抓包,点击上传的时候,弹出对话框,可是流量并没有经过代理软件bp,由此我们猜想为前端上传的限制,我们查看源码发现,里面有个js的上传限制函数
找到元素中这个函数,直接删除
再点击上传,成功上传,这是我们就可以在页面元素中查看上传的文件地址,进行访问
方法2
或者我们先上传一个png的文件,再抓包改为php的后缀就能绕过
方法3
bp设置自动剔除前端js,就可以直接上传上传成功 bp剔除js
Pass-02 - Content-Type检测
限制函数如下,通过读取文件的类型type来判断是否合法,即读取请求头中Content-Type类型的值,只需要修改Content-Type值符合要求就能上传
原理:其content-type(mime)是由客户端根据你上传的文件生成的
如下,修改Content-Type值,即可以上传成功
黑名单检测
Pass-03
源码如下,上面部分定义了个黑名单(.asp, .aspx, ...),对文件名删除末尾的点,截取文件的后缀。将获取的文件的后缀匹配黑名单,如果匹配上了则上传失败,所以我们可以上传黑名单外的文件。如php3
上传不在黑名单中的文件后缀,如php3,php5,phtml等
Pass-04 - .htaccess
将黑名单进行了扩充,如果没在黑名单中,则进行上传,但是.htaccess没在黑名单中,所以可以上传.htaccess文件 ——> 关于.htaccess攻击_北遇-CSDN博客
方法一:.htaccess
采用黑名单限制的方式,观察代码发现未过滤.htaccess文件
1. 把png文件当做php文件来执行
2. 再上传一个png文件,内容为php代码
3. 访问图片
方法二:apache文件名解析漏洞
利用Apache 文件名解析漏洞(5.2.x以下)(info.php.x 绕过)可以绕过,传送门-》apache文件名解析漏洞
Pass-05 - .user.ini
此关增加了对.htaccess的过滤,但是没有过滤.php7和.ini文件
所以可以上传php7后缀的文件以及.user.ini文件,此关考察的是利用.user.ini文件构建php后门,传送门——> 利用.user.ini构建php后门
Pass-06 - 大写后缀PHP绕过
此关也是黑名单过滤的方式,黑名单中没有过滤大写的后缀,且对上传的后缀没有转换为小写。所以我们上传一个shell.PHP即可绕过
Pass-07 - 空格绕过
观看源码此关还是黑名单检测,我们发现没有对文件名首尾去空格,所以我们可以在后缀后面加个空格就能绕过检测。而文件上传到服务器中,又会自动去掉空格
上传文件后截取包,在后缀后面加上空格
Pass-08 - 点绕过
也是黑名单检测,源码中文件后缀过滤了空格,但是没有过滤点,所以文件后缀后面加点或者点空格点都能绕过
Pass-09 - ::DATA
也是黑名单检测,没有过滤::$DATA。
在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,他的目的就是不检查后缀名
例如:"phpinfo.php::$DATA"Windows会自动去掉末尾的::$DATA变成"phpinfo.php"
Pass-10 - 点空格点绕过
也是黑名单检测,源码中文件后缀过滤了点和空格,所以后缀加点空格点即可以绕过
Pass-11 - 双写绕过
将文件后缀与黑名单中的词进行匹配,匹配成功则替换为空。所以我们可以双写后缀进行绕过
白名单检测
Pass-12 - GET型00截断
从这一关开始将进入白名单
- 原理:因为在C语言中%00是字符串的结束标识符,而PHP就是C写的,所以继承了C的特性,所以判断为%00是结束符号不会继续往后执行
利用条件
- PHP<5.3.29,且GPC关闭
- 能够自定义上传路径
漏洞利用
1. php切换到5.2.17
2. 关闭GPC,关于GPC——> get_magic_quotes_gpc()
打开对应的php.ini文件将GPC关闭,然后重启服务器
3. 源码分析
看到是白名单判断,我们可以控制上传的路径
但是$img_path直接拼接,因此可以利用%00截断绕过。先修改path值,为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:../uploads/1.php%00/1.png
,移动文件的时候会将文件保存为../uploads/1.php
,从而达到Getshell效果。
详情可看:关于上传中的00截断分析
Pass-13 - POST型00截断
这一关和上一关的区别是,00截断是用在POST中
POST不会像GET那样对%00进行自动解码。
1. 修改post路径为../upload/14.php,再点击hex
2. 使用burpsuite对%00进行解码
3. 点击forward
Pass-14 - 图片马
本关要求上传图片马。图片马们可以结合文件包含漏洞进行使用,利用文件包含漏洞的无条件解析文件名的特性,传送门 -》文件包含
观看源代码,发现其先以二进制的方式打开图片,然后读取前两个字节的内容,根据前两个字节来判断图片类型
1. 上传jpg图片马
先找一张正常的图片,因为正常的图片肯定符合其图片类型的。再做图片马 ——>
图片马的生成方式
2. 结合文件包含
包含上传的图片马
Pass-15 - 图片马
源码如下,这里使用的是 getimagesize()函数获取图片信息,利用方式和上关一样
getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息
Pass-16 - 图片马
本关使用了 exif_imagetype函数,用户判断图片的类型
1. 需要开启php_exif模块
打开php.ini文件,去掉去下的注释,将其开启
extension=php_exif.dll
2. 上传图片马,和上关一样
Pass-17 - 图片马
未完~