知识点
文件上传常见验证:后缀名,类型,文件头等
1.后缀名:黑名单,白名单
- 黑名单:明确不让上传的格式后缀,比如asp,php,jsp,aspx,cgi,war等,但是黑名单易被绕过,比如上传php5,Phtml等
- 白名单:明确可以上传的格式后缀,比如jpg,png,zip,rar,gif等,推荐白名单。
2.文件类型:MIME信息
- content-type字段校验,可以通过抓包改包方式绕过
3.文件头:内容头信息
- 每种类型的文件都有自己固定的文件头信息,比如GIF89a是gif图片的文件头信息,可以通过手动在脚本文件前面增加文件头的方式绕过。
4.windows特性
- windows下文件名不区分大小写,linux下文件名区分大小写
- windows下NTFS 特征,导致上传文件xxx.php::$DATA = xxx.php
- windows下文件名结尾加入“.”、“空格”、“<”、“>”、“>>>”、“0x81-0xff”等字符,最终生成的文件均被windows忽略。
upload-labs
- 下载:https://github.com/c0ny1/upload-labs
- 1.GET优先于POST
- 2.搭建upload 靶场时 php环境尽量选低,要不然会出现访问木马文件出现下载的现象
- 案例1:Pass-1 $_FILES[‘upfile’]访问文件的有关信息
- 案例2:Pass-2 MIME-Type验证
- 案例3:Pass-3 黑名单绕过 特殊解析后缀
- 案例4:Pass-4 .htaccess绕过
- 案例5:Pass-5 大小写绕过
- 案例6:Pass-6 后缀名空格绕过
- 案例7:Pass-7 点绕过
- 案例8:Pass-8 ::$DATA绕过
- 案例9:Pass-9 点+空格+点绕过(循环递归过滤)
- 案例10:Pass-10 双写绕过
- 案例11:Pass-11 %00截断 GET请求
- 案例12:Pass-12 00截断 POST请求
案例演示
Pass1:$_FILES[‘upfile’]访问文件的有关信息
$_FILES[‘upfile’][‘name’]; //客户端上传文件的原名称,不包含路径
$_FILES[‘upfile’][‘type’]; //上传文件的MIME类型
$_FILES[‘upfile’][‘tmp_name’]; //已上传文件在服务器端保存的临时文件名,包含路径
$_FILES[‘upfile’][‘error’]; //上传文件出现的错误号,为一个整数
$_FILES[‘upfile’][‘size’]; //已上传文件的大小,单位为字节
- 我们首先进行第一关的尝试,通过f12将网页代码复制下来发现验证代码时用前端js编写的
- 这时候我们在自己本地新建一个文件(存放我们的第一关,防止误删其他重要代码),在代码中我们将验证部分删掉,同时加上对应的提交位置
- 添加上传到的位置
-
- 进行上传操作,在对应文件看到php文件,成功上传!
- 第二个思路:利用bp抓包进行修改,将后缀直接改成php即可实现上传脚本文件操作
- 我们首先进行第一关的尝试,通过f12将网页代码复制下来发现验证代码时用前端js编写的
- 案例2:Pass-02 MIME-Type验证
- MIME(multipurpose Internet mail extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
- 查看代码,系统校验了MIME-Type
-
- 因此只要抓包修改content-type值为符合条件的值即可绕过。
-
- 修改为:image/jpeg
-
- 然后发包,我们发现已经成功上传
[blockquote2 name='附各类文件MIME_type对照表 ']
- {".3gp", "video/3gpp"},
- {".apk", "application/vnd.android.package-archive"},
{".asf", "video/x-ms-asf"}, {".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"}, {".bmp", "image/bmp"}, {".c", "text/plain"}, {".class", "application/octet-stream"}, {".conf", "text/plain"}, {".cpp", "text/plain"}, {".doc", "application/msword"}, {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {".xls", "application/vnd.ms-excel"}, {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {".exe", "application/octet-stream"}, {".gif", "image/gif"}, {".gtar", "application/x-gtar"}, {".gz", "application/x-gzip"}, {".h", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".jar", "application/java-archive"}, {".java", "text/plain"}, {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".js", "application/x-javascript"}, {".log", "text/plain"}, {".m3u", "audio/x-mpegurl"}, {".m4a", "audio/mp4a-latm"}, {".m4b", "audio/mp4a-latm"}, {".m4p", "audio/mp4a-latm"}, {".m4u", "video/vnd.mpegurl"}, {".m4v", "video/x-m4v"}, {".mov", "video/quicktime"}, {".mp2", "audio/x-mpeg"}, {".mp3", "audio/x-mpeg"}, {".mp4", "video/mp4"}, {".mpc", "application/vnd.mpohun.certificate"}, {".mpe", "video/mpeg"}, {".mpeg", "video/mpeg"}, {".mpg", "video/mpeg"}, {".mpg4", "video/mp4"}, {".mpga", "audio/mpeg"}, {".msg", "application/vnd.ms-outlook"}, {".ogg", "audio/ogg"}, {".pdf", "application/pdf"}, {".png", "image/png"}, {".pps", "application/vnd.ms-powerpoint"}, {".ppt", "application/vnd.ms-powerpoint"}, {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {".prop", "text/plain"}, {".rc", "text/plain"}, {".rmvb", "audio/x-pn-realaudio"}, {".rtf", "application/rtf"}, {".sh", "text/plain"}, {".tar", "application/x-tar"}, {".tgz", "application/x-compressed"}, {".txt", "text/plain"}, {".wav", "audio/x-wav"}, {".wma", "audio/x-ms-wma"}, {".wmv", "audio/x-ms-wmv"}, {".wps", "application/vnd.ms-works"}, {".xml", "text/plain"}, {".z", "application/x-compress"}, {".zip", "application/x-zip-compressed"}, {"", "*/*"}[/blockquote2]
- 案例3:Pass-3 黑名单绕过 特殊解析后缀
- 查看源码,发现源码配置了黑名单,不允许上传.asp,.aspx,.php,.jsp后缀的文件
-
- 但apache服务器能够使用php解析.phtml .php3 .php5。前提是apache的httpd.conf中有如下配置代码
- AddType application/x-httpd-php .php .phtml .php3 .php5
- 因此可以上传.phtml .php3 .php5文件,绕过黑名单
-
- 案例4:Pass-4 .htaccess绕过
- 查看源码,发现源码配置了黑名单,拒绝了几乎所有有问题的后缀名,除了.htaccess
-
- .htaccess作为局部变量成功作用于当前目录下文件的两个条件(1.启用AllowOverride,2.开启mod_rewrite模块)
- 修改httpd.conf:
1、Allow Override All
2、LoadModule rewrite_module modules/mod_rewrite.so
- 修改httpd.conf:
本关正好符合,因此先上传一个.htaccess文件,内容如下:
<FilesMatch "hello">
setHandler application/x-httpd-php
</FilesMatch>
作用是使当前目录下所有文件名包含“hello”字符串的文件当作php文件解析。-
- 然后再上传一个hello.jpg文件,内容如下:<?php phpinfo(); ?>
-
- 此时访问该文件web路径,服务器执行hello.jpg文件中的PHP代码。
- 案例5:Pass-5 大小写绕过
- 查看源码
-
- 发现没有strtolower函数将大小写转换,可以利用大小写绕过
- 抓包修改后缀为大写
-
- 然后上传成功
- 案例6:Pass-6 后缀名空格绕过
- 原理是 服务器在校验黑名单时,校验的后缀名是.php+空格,由于.php+空格不在黑名单内,可以通过校验,而windows系统在保存文件时,会自动去掉后面的空格,因此文件最终保存在服务器上的后缀名为.php。(linux系统在保存文件时应该也会自动去除空格,可以自行测试一下?)
- 查看源码
-
- 发现没有trim函数去除末尾空格,在php后面加一个空格
-
- 然后上传成功
- 案例7:Pass-7 点绕过
- 查看源码
-
- 源码相较于pass-4,没有deldot函数删除文件名末尾的点,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.空格.”绕过。
-
- 案例8:Pass-8 ::$DATA绕过
- 补充知识:deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来
- 查看源码
-
- 源码相较于pass-4,没有str_iplace函数对后缀名中的“::$DATA”进行过滤。在php+windows的情况下,如果文件名+“::$DATA”会把“::$DATA”之后的数据当成文件流处理,不会检测后缀名,且保持“::$DATA”之前的文件名。利用windows特性,可在后缀名后面加“::$DATA”绕过。例如“phpinfo.php: :$DATA” Windows会自动去掉末尾的“::$DATA”变成“phpinfo.php”。
- 在php后面加 :空格:$DATA
-
- 案例9:Pass-9 点 空格 点 绕过
- 查看源码
-
- 发现他把之前的漏洞都补上了,但他代码本身就有问题 : 只过滤了 一个 点 和 一个 空格 还有PATH :
- 首先需要了解deldot函数,当deldot函数检测到末尾的第一个点时将继续从后向前检测,当检测到空格时就停下来,因此当后缀是
php.[空格].
时,经过deldot函数过滤后,后缀变成php.[空格]
,最终绕过黑名单,且上传上去的文件名为php.
,在windows下会自动去除点。 - 所以, 可以用 bs 将1.php 改为 1.php. . (点+空格+点) 成功绕过
-
- 这里发现
$_FILES['upload_file']['name']
获取的是文件名中/
后面的字符串,本来还想用但move_uploaded_file
会忽略/.
的trick绕过
- 案例10:Pass-10 双写绕过
- 操作过程:查看源代码 发现 依旧是黑名单过滤 关键过滤就这两句:
-
- 当file_name中出现deny_ext中存在的字符串,就把它去掉,但只处理了一次.
- 可以用双写后缀名 进行绕过 将1.php 改为 1.pphphp 成功绕过
-
- 案例11:Pass-11 %00截断 GET请求
- 操作过程:查看源代码,发现是白名单过滤
-
- 但是
img_path
直接使用点号拼接路径,这里就存在风险. $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
我们可以使用
%00截断
来实现绕过.
- php版本5.5.9
- php的magic_quotes_gpc为OFF状态
- 但这东西有点过气了,因为需要以上两个条件
- 如果要完成这一个题目就必须要实现上面的两个条件,但是现在都PHP7了,这东西也就很少见了,满足上面的条件的时候php就是把它当成结束符,后面的数据直接忽略
-
- Pass-12 00截断 POST请求
- 查看代码,发现和11关一样,只不过get请求换为了post请求
-
- 上传php文件后,抓包在在a.php后面加一个空格
-
- 然后将空格的十六进制 20 改为 00 ,上传即可
- 然后上传,发现成功!
-