文件上传
1什么是文件上传
文件上传就比如上传用户头像,上传图片,上传附件等。在服务端实现文件上传功能时,如果对用户上传的文件没有做好处理,就有可能导致十分严重的安全问题,比如被上传木马文件造成RCE(远程代码执行)
php文件上传的基本代码
```php
<?php
$file=$_FILES['file'];
move _uploaded_file($file[' tmp_name'],$file[ 'name']);
echo $file['name'];
```
PHP的文件上传,通常使用$_FILES配合move_uploaded_file实现。如果直接使用用户的文件名作为保存的文件名,直接保存在web可访问的目录中,就造成了任意文件上传漏洞。
2 文件名截断绕过
1.00截断
00截断是很早之前的一种绕过上传限制的方法,需要PHP版本小于5.4.39.
00截断是move_uploaded file函数的第二个参数dest,在处理字符时,如果该字符串中间有“\x00”字符,会发生截断。比如"1.php\x00.jpg",因为PHP本身的字符串是二进制安全的(字符串可以保存\x00字符),在php代码中检测扩展名会获取到".jpg",但是在移动后会变成“1.php”
这种文件上传的00截断还有一个限制是,从$_FILES['file']['name’]中取出的文件是不包含"\x00"的,也就是说只有下面的代码才有可能出现00截断的文件上传漏洞。
```php
<?php
$file = $_FILEs['file'];
$dir =$_POST['dir'];
move_uploaded_file($file['tmp_name'],$dir.'/'.$file['name']);
echo $file['name'];
```
2.转换字符集造成的截断
虽然$_FILES['file’]['name]不会出现"x00"字符,但是在进行字符集转换时仍有可能发生截断。PHP实现字符集转换常用iconv()函数,UTF-8单字节允许的字符范围为"\x00"-"\x7f",如果被转换的字符不在该范围内,会造成PHP_ICONV_ERR_ILLEGAL_SEQ异常,在PHP版本小于5.4时,出现该异常后,就不会继续处理后续字符,造成截断。
3文件扩展名黑名单绕过
在上传文件时,通过检测上传文件的扩展名是否在黑名单中,如果在黑名单中则拒绝上传。这种黑名单检测主要有两种场景。
1.上传文件重命名
代码对上传的文件扩展名进行了检测,如果在黑名单中就拒绝上传。并且将上传的文件名进行了重命名。在这种场景下,可以使用一些较为冷门但可以被解析的扩展名进行绕过。
比如PHP的php3、php5、phtml、pht等(但是有限制,受限于web服务器,要求服务器能认识)。ASP可识别的有cdx、cer、asa等。JSP可识别的jspx等
还可以利用一些操作系统的特性,比如windows中的"php::$DATA","PHP"
2.上传文件不重命名
在这种场景下,除了利用一些冷门但可以解析的扩展名之外,还可以通过上传".htaccess"或".user.ini"等配置文件实现绕过。
a.上传.htaccess
".htaccess"是Apache服务器分布式配置文件的默认名称。在Apache主配置文件中通过"AllowOverride"指令配置”.htaccess”文件中可以广用哪些指令。在Apache低于"2.3.8"的版本中默认为"AI”,在高版本中为"None"。
在Apache版本小于2.3.8时,可以尝试上传".htaccess",使用"SetHandler"指令使PHP解析其他扩展名的文件。
```
l <FilesHatch "a png">
2 setHandler application/x-httpd-php
3 </FilesMatch>
```
b.上传.userini
自PHP 5.3.0起支持基于每个目录的".htaccess"风格的INI文件,此类文件仅被CGI/FastCGl处理,默认文件名为".user.ini"。为了保证安全性,".user.ini"不能覆盖"php.ini"中的所有配置。在"https://www.php.net/manual/zh/ini.list.php“中可以査看所有的配置选项的配置范围。
在PHP INIPERDIR可配置的选项中,存在一个特殊配置"auto_prepend file"