前端检测
主要是通过javascript代码进行检测,非常容易进行绕过。
原理
Web应用系统虽然对用户上传的文件进行了校验,但是校验是通过前端javascript代码完成的。由于恶意用户可以对前端javascript进行修改或者是通过抓包软件篡改上传的文件,就会导致基于js的校验很容易被绕过。
如何判断当前页面使用前端is的验证方式
前端验证通过以后,表单成功提交后会通过浏览器发出─条网络请求,但是如果前端验证不成功,则不会发出这项网络请求;可以在浏览器的网络元素中查看是否发出了网络请求。
绕过方法
- 删除或者禁用js:
火狐浏览器-->about:config-->JavaScriptenable-false (ajax) - 使用代理上传文件,Burp Suite;上传符合要求的文件类型,抓包修改文件类型。
- 直接删除代码中onsubmit事件中关于文件上传时验证上传文件的相关代码即可或者可以不加载所有js,还可以将html源码copy一份到本地,然后对相应代码进行修改,本地提交即可。
CTFHub-web-文件上传-前端验证
首先查看源码发现发现只允许jpg等几种后缀名文件通过,所以先将所要上传的文件后缀名改为jpg形式进行上传,中途用bp抓包,如下:

将filename改为test.php,然后发送:

发现文件上传成功,然后打开蚁剑进行连接,获取到flag文件,打开即可看到flag
绕过Content-Disposition
在常规 HTTP 响应中 Content-Disposition ,响应标头是一个标头,指示内容是应在浏览器中以内联方式显示,即作为网页或网页的一部分,还是作为附件在本地下载和保存(这操作当然是在文件成功上传后,但是你无法通过正常的途径去访问)
举个例子:Content-Disposition: attachment; filename="filename.jpg"
上述响应Content-Disposition 的属性 attachment 表示告诉浏览器将内容作为附件下载。另外,filename="filename.jpg" 指定了下载的文件名为 filename.jpg
为了让我们的文件可以传上去,而不是被下载下来,我们可以用CRLF漏洞来进行绕过,即在我们可控的响应头内输入 \r\n\r\n或者是将其编码后的 %0d%0a%0d%0a,举个例子,如果说报头中的Content-Type可控,那么我们在后面键入text/html\r\n\r\n,就可以实现绕过,这是由于注入的回车符和换行符导致浏览器将 content-disposition 标头解释为 HTTP 正文的一部分,因此被忽略为告诉浏览器下载的指令,当然,使用 %00也可以达到相同的效果,下面我们来自己测试一下:
1 |
|
正常在url后面输入?file=show.txt&header=show.txt&type=text/plain去访问的话会直接将文件下载下来,在hackbar或者bp里面自己访问的话并不会,然后如果我们输入?file=show.txt&header=show.txt%0d%0a%0d%0a&type=text/plain的话页面回显如下:
第一行的警告其实涉及到了php底层的c源码,如下:
我们试图往header里插入\r或者\n,会直接抛出异常,这一句直接失效,这其实是CRLF的另一种绕过姿势
当我们输入?file=show.txt&header=show.txt%00&type=text/plain时,页面回显如下

这第一行的警告里面也涉及到了php的底层c源码,如果是%00的话会抛出异常,如下

但是我们输入 ?file=show.txt&header=show.txt&type=text/plain%00的话,页面回显如下

那么为什么我们在type处输入%00,明明只是影响到Content Type的值,却还是把Content disposition给干掉了呢?这是因为第二个异常,通过搜索得知抛出第二个异常是因为header在执行的时候有任何数据被带到浏览器,而在这一数据就是指第一个异常,所以第二个header并不会执行
后端检测
MIME检测
什么是MIME
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。
常见的MIME类型
text/plain (纯文本)
text/html (HTML文档)
text/javascript (js代码)
application/xhtml+xml (XHTML文档)
image/gif (GIF图像)
image/jpeg (JPEG图像)
image/png (PNG图像)
video/mpeg (MPEG动画)
application/octet-stream (二进制数据)
application/pdf (PDF文档)
检测方式
在文件上传过程中,服务端会针对我们的上传的文件生成一个数组,这个数组其中有一项就是这个文件的类型file_type;服务端对文件进行检测时,就是通过检测脚本中的黑白名单和这个数组中的file_type进行对比,如果符合要求就允许上传这个文件。

MIME绕过的原理
部分Web应用系统判定文件类型是通过content-type字段,黑客可以通过抓包,将content-type字段改为常见的图片类型,如image/gif,从而绕过校验。
CTFHub-web-文件上传-MIME检测
首先上传php文件弹窗文件类型不正确,检查源码发现并没有相关js代码,所以应该是后端
文件上传途中进行抓包,将 content-type字段改为 image/gif,然后发送请求包,上传的文件名后缀不需要改变

文件上传成功,然后就可以启动蚁剑了,蚁剑的密码为$_POST里面的内容,上传的文件内容如下:
1 |
|
00截断
原理
虽然web应用做了校验,但是由于文件上传后的路径用户可以控制,攻击者可以利用手动添加字符串标识符0X00的方式来将后面的拼接的内容进行截断,导致后面的内容无效,而且后面的内容又可以帮助我们绕过黑白名单的检测。
条件
- - php版本要小于5.3.4,5.3.4及以上已经修复该问题
- - PHP的magic_quotes_gpc为OFF状态
- - 用户可指定上传路径并且上传路径通过GET方式传参
绕过思路
在C语言中,空字符有一个特殊含义,代表字符串的拼接结束。这里我们使用的是php语言,属于高级语言,底层靠C语言来实现的,也就是说空字符的字符串拼接结束功能在PHP中也能实现。但是我们在URL中不能直接使用空,这样会造成无法识别;我们通过查看ASCII对照表,发现ASCII对照表第一个就空字符,它对应的16进制是00,这里我们就可以用16进制的00来代替空字符,让它截断后面的内容。
使用burpsuite进行抓包,因为这里是通过URL进行传递的文件上传后存储路径,所以需要对16进制的00进行URL编码,编码的结果就是%00,通过这种方式,就可以%00截断后面的内容,让拼接的文件名不再进行生效
题目
首先查看相关源码:
1 | if (!empty($_POST['submit'])) { |
in_array($ext, $whitelist):in_array($ext, $whitelist) 是 PHP 中用于检查一个值是否存在于数组中的函数。$ext 是要检查的值,$whitelist 是要检查的数组。如果 $ext 存在于 $whitelist 数组中,则该函数返回 true;否则返回 false
move_uploaded_file($_FILES['file']['tmp_name'], $des):
move_uploaded_file(): 这是 PHP 中用于将上传的文件移动到新位置的函数。它接受两个参数:源文件路径和目标文件路径。$_FILES['file']['tmp_name']: 这是上传文件在服务器上的临时存储路径。在 PHP 中,通过$_FILES超全局变量可以访问到上传的文件信息,其中'file'是表单中<input type="file">控件的 name 属性值,'tmp_name'表示上传文件的临时存储路径。$des: 这是目标文件的路径,是之前代码中生成的文件路径。它是目标位置,上传的文件将被移动到这个位置。
根据上面的代码思路,首先我们把文件后缀名改为jpg形式,然后用bp抓个包然后修改get传参中的road值,如下所示:

上传成功,使用蚁剑获取到flag
POST传参保存路径
与GET传参类似的的是:后端对文件路径的处理类似为
1 | PHP |
此时road为我们可控的参数,但与GET传参不同的是,http请求内包含文件时,POST参数不再被自动解码,所以POST传参需要使用BP使用查看16进制的请求详情,修改一个十六进制的为00

步骤一:修改路径添加文件名,写入需要执行的代码语句

步骤二:切换为十六进制模式,修改所需要替换为00的位置

由于使用00截断,所以最后文件保存在/var/www/html/upload,名为test.php,根据位置,访问/upload/test.php,即进入我们所在的页面,可以看到PHP的配置信息,00截断成功
文件头检测漏洞
原理
在每一个文件(包括图片,视频或其他的非ASCII文件)的开头(十六进制表示)实际上都有一片区域来显示这个文件的实际用法,这就是文件头标志。我们可以通过16进制编辑器打开文件,添加服务器允许的文件头以绕过检测。
另一种方法就是用画图软件画一张简单的图,太复杂的话会报错,然后抓包在文件末尾添加php代码
常见的文件头
注意:下面的文件头的格式是16进制的格式:
GIF:47 49 46 38 39 61 png:89 50 4E 47 0D 0A 1A 0A JPG:FF D8 FF E0 00 10 4A 46 49 46
在进行文件头绕过时,我们可以把上面的文件头添加到我们的一句话木马内容最前面,达到绕过文件头检测的目的
CTFHub 文件上传 - 文件头检测
最开始上传一个.php后缀的文件,提交,alert()弹出一个窗口,只允许jpg,png,gif后缀提交,然后burpsuite抓包,把Content-type改为image/png,然后发现还是上传不上去,有弹窗,发现有文件头检测
首先用画图工具做出一个最简单的图,太复杂的话会报错,然后上传,中途抓包修改数据如下:
报头中的文件后缀名要改回 php,然后发送请求包,成功
之后利用蚁剑获取到flag
内容检测图片马绕过
漏洞原理
一般文件内容验证使用getimagesize函数检测,会判断文件是否是一个有效的文件图片,如果是,则允许上传,否则的话不允许上传。 本实验就是将一句话木马插入到一个[合法]的图片文件当中,然后用webshell管理工具(比如蚁剑)进行远程连接。
图片马制作
准备一张图片,这里为a.png,和一个一句话木马,通过以下命令合成一个图片马3.jpg: a.php内容:
1 | phpinfo(); |
命令(用cmd,在文件所在的目录):
1 | copy a.png /b + a.php /a 3.jpg |
注:这条命令的意思是:通过copy命令,把a.png图片文件,以二进制文件形式添加到a.php文件中,以ASCII文本文件形式输出为3.jpg文件。
解析图片马
一般解析图片马需要结合解析漏洞或者文件包含才能解析图片马
常见漏洞
.htaccess文件解析漏洞
什么是.htaccess文件
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
漏洞利用前提
web具体应用没有禁止.htaccess文件的上传,同时web服务器提供商允许用户上传自定义的.htaccess文件。
原理
.htaccess文件(或者"分布式配置文件") ,全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法,即,在一个特定的文档目录中放置一个包含一个或多个指令的文件,以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
利用方式
一般.htaccess可以用来留后门和针对黑名单绕过
上传覆盖.htaccess文件,重写解析规则,将上传的带有脚本木马的图片以脚本方式解析。
.htaccess文件内容
.htaccess文件解析规则的增加,是可以按照组合的方式去做的,不过具体得自己多测试。
1 | <FilesMatch "evil.gif"> |
或者是以下内容
1 | AddType application/x-httpd-php .txt |
这段 Apache 配置语法用于将指定扩展名的文件类型设置为 PHP 文件类型。
AddType: 这是 Apache 配置指令,用于将文件扩展名关联到指定的 MIME 类型。application/x-httpd-php: 这是 MIME 类型的标识符,表示 PHP 文件类型。.txt: 这是要关联的文件扩展名,表示文本文件
CTFHub 文件上传 - htaccess
配置文件 .htaccess文件文件名只能是这个,但是在windows系统中不能够直接这样命名,文件名不能为空,从网上发现可以通过另一种方法来修改:开启cmd,切换到文件所在的目录,然后通过rename直接修改:rename 1.htaccess .htaccess
.user.ini漏洞
php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。 但是这种方式其实是有个前提的,因为.user.ini只对他同一目录下的文件起作用,也就是说,只有他同目录下有php文件才可以。
1 | .user.ini文件内容: |
ctfshow-web153
url上输入 /upload,网页显示了nothing here表示可以用配置文件(因为upload目录下有php文件)
为了利用auto_append_file,我们首先上传.user.ini内容为 auto_append_file=“xxx” xxx为我们上传的文件名,接着上传一个带木马的图片 因为upload有index.php,所以这个php就会添加一个include(“shell.png”),就会包含到木马,这样就在每个php文件上包含了我们的木马文件
构造两个文件内容如下:
1 | .user.ini.png |
开始做题:
先上传.user.ini.png文件,并抓包,修改名称:.user.ini,然后放包
接着再上传图片马,最后就可以用蚁剑连接 /upload/,然后获取到flag
ctfshow-web154&155
首先按照上题步骤上传 .user.ini文件成功,然后上传图片马失败,根据题解说是过滤了php,于是可以试试短标签,如下:
1 | 可用使用<?=(表达式)?>进行绕过,<?=(表达式)?> 等价于 <?php echo (表达式)?> |
于是图片内容变为:<?=eval($_POST[shell]);?>,上传成功,用蚁剑连接一下 /upload/,然后获取到flag
ctfshow-web156
首先按照上题步骤上传 .user.ini文件成功,然后上传图片马失败,自己测试实在没有发现过滤了什么,看了提及人后才明白过滤掉了[],在php中查看数组也可以用{},所以只要把图片马内容中的[]全部改成{},然后再上传就可以了
ctfshow-web157&158
[] {}, ; 都被过滤了,导致不能使用蚁剑来进行连接,所以我们直接远程代码执行
首先按照上面几题一样先上传 .user.ini文件,然后先上传图片马内容为:<?=system('ls ../')?>查看到flag的位置,因为php也被禁止掉了,所以我们可以使用通配符???或者*来代替php,内容为:<?=system('cat ../flag.*|base64')?>,再拿去base64解码后就可以得到flag了
Apache解析漏洞
此漏洞实际为人为的错误配置导致的漏洞,与Apache本身无关
Apache对多后缀文件的识别概括来说为:
Apache允许文件有多个扩展名,并且会将所有后缀名进行识别,识别的顺序为:从右到左
- 如:
.html.fr映射到Content-Type: text/html和Content-Language: de。
- 如:
Apache允许扩展名映射到元数据(包括:语言、内容类型、字符集或编码)、处理程序。
- 如
.html映射到Content-Type: text/html。
- 如
对于相同类型元数据,以从右到左第一个出现的为准,但对于语言和内容编码可累积的元数据,将会叠加
如:.
gif.html根据此规则映射到Content-Type: text/html。.html.en.de根据此规则映射到Content-Language: en, de和Content-Type: text/html由于映射到处理程序和映射媒体类型,最后的返回结果不一致(一个为经过程序处理,一个为返回媒体文件)。当出现不同扩展名映射到处理程序和媒体类型时,映射到处理程序的优先等级高于映射到媒体类型
如:
.imap.html扩展名.imap映射到处理程序imap-file,.html映射到Content-Type: text/html,根据上述原则,.imap.html文件会被imap-file程序处理
使用 Add* 指令,Apache处理一个文件时会应用上述规则
Add* 指令指的是如:AddType、AddDefaultCharset、AddEncoding、AddHandler、AddOutputFilter、AddLanguage、AddCharset等指令,其中AddHandler设置对应后缀名映射到处理程序,如:
1 | AddHandler application/x-httpd-php .php |
由此,当用户上传一个a.php.jpg文件时,Apace的配置文件中包含AddHandler处理PHP文件,且未对上传后的文件进行重命名,此时a.php.jpg被解析为一个PHP脚本,解析漏洞由此而来
解析配置漏洞条件
- 文件没有被重命名
- Apache中配置中含有
AddHandler的设置
解析配置漏洞解决办法
- 将上传的文件进行重命名
- 根据官方文档的说明,可以使用
SetHandler指令来代替AddHandler,因为SetHandler仅根据最右端的后缀名来判断映射的处理程序
影响版本
apache 1.x apache 2.2.x
IIS6.0解析漏洞
IIS6.0解析漏洞分两种: 1、目录解析: 以xx.asp命名的文件夹里的文件都将会被当成ASP文件执行。 2、文件解析: xx.asp;.jpg 像这种畸形文件名在;后面的直接被忽略,也就是说当成xx.asp文件执行。
IIS6.0 默认的可执行文件除了asp还包含这三种 .asa .cer .cdx。
IIS7.0 | IIS7.5 | Nginx的解析漏洞
原理
Nginx拿到文件路径(更专业的说法是URI)/test.jpg/test.php后,一看后缀是.php,便认为该文件是php文件,转交给php去处理。php一看/test.jpg/test.php不存在,便删去最后的/test.php,又看/test.jpg存在,便把/test.jpg当成要执行的文件了,又因为后缀为.jpg,php认为这不是php文件,于是返回Access denied。 这其中涉及到php的一个选项:cgi.fix_pathinfo,该值默认为1,表示开启。开启这一选项PHP可以对文件路径进行修理。
举个例子,当php遇到文件路径/1.jpg/2.txt/3.php时,若/1.jpg/2.txt/3.php不存在,则会去掉最后的/3.php,然后判断/1.jpg/2.txt是否存在,若存在,则把/1.jpg/2.txt当做文件/1.jpg/2.txt/3.php,若/1.jpg/2.txt仍不存在,则继续去掉/2.txt,以此类推。
漏洞形式
1 | www.xxxxx.com/UploadFiles/image/1.jpg/1.php |
另外两种解析漏洞
1 | www.xxxxx.com/UploadFiles/image/1.jpg%00.php` `www.xxxxx.com/UploadFiles/image/1.jpg/%20\0.php |
条件竞争漏洞
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
1.访问时间点在上传成功之前,没有此文件。
2.访问时间点在刚上传成功但还没有进行判断,该文件存在。
3.访问时间点在判断之后,文件被删除,没有此文件。
二次渲染漏洞
二次渲染原理
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
绕过
1、配合文件包含漏洞: 将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。 2、可以配合条件竞争: 这里二次渲染的逻辑存在漏洞,先将文件上传,之后再判断,符合就保存,不符合删除,可利用条件竞争来进行爆破上传
如何判断图片是否进行了二次处理
对比要上传图片与上传后的图片大小,使用16进制编辑器打开图片查看上传后保留了哪些数据,查看那些数据被改变。
利用文件上传实现日志包含从而连接蚁剑
bp实战
Lab:通过 Web Shell 上传远程执行代码
题目要求:请上传一个基本的 PHP Web Shell 并使用它来泄露文件 /home/carlos/secret 的内容。使用实验室横幅中提供的按钮提交此机密
首先我们先登录账号,发现有个头像图片上传功能,开启proxy插件,先上传一个正常的图片,然后到代理模块中的http历史记录,选中/my-account/avatar条目发送到重放器中,然后更改过滤器配置如下:

应用发现多了一条目,是显示图片的,也发送到重放器中
第一个文件修改成如下内容:

然后第二个文件更改一下filename,再发送一遍,便得到了所需要的机密
Lab:通过绕过 Content-Type 限制上传 Web shell
和上题不一样的地方就是多了对Conten-Type的检查,要求必须是图片类型的才可以
其余的操作步骤与上题一致,需要注意的是eval函数里面直接接语句的话要有双引号包括才可以
Lab:通过路径遍历进行Web shell上传
要求:该实验室包含一个存在漏洞的图像上传功能。服务器被配置为阻止执行用户提供的文件,但可以通过利用第二个漏洞来绕过此限制。要完成该实验,请上传一个基本的 PHP Web shell 并使用它来窃取文件 /home/carlos/secret 的内容。使用实验室横幅中提供的按钮提交此机密
首先如果我们直接按照前两题的步骤来做该题的话,会发现页面会直接回显给我们输入的代码内容,并不会执行
发现上传图片的模块中的filename可以随意修改,所以我们尝试给该文件换个地方,如下:

发现我们输入的被直接处理掉了
再尝试一下进行url编码试试,如下:
成功上传该文件,于是我们去访问一下该文件,结果如下:
拿到机密,题目解决
Lab:通过扩展黑名单绕过上传Web shell
正常上传一个文件后,我们将其改为php后缀的文件再次进行上传,发现页面会回显不允许php后缀的文件上传
于是尝试将后缀名改为.php4,成功上传,但发现页面会直接回显给我们输入的代码内容,并不会执行该代码
这时候我想到了可以通过上传.user.ini文件来进行绕过,于是进行尝试,但是发现页面还是直接回显输入的代码内容(不知道为什么行不通)。万幸我们还有另一种方法,可以通过上传.htaccess来绕过,该文件具体内容如下:
1 | AddType application/x-httpd-php .txt |
后缀为.txt的文件都会被当作php代码执行,于是我们上传

然后bp访问该url,得到机密,解决题目
Lab:通过混淆的文件扩展名上传 Web shell
最开始是想着按照上题的思路先上传一个.htaccess文件,但是上传失败,页面回显只允许后缀名为png或者jpg的文件上传
但是这题的filename我们是可以改的,所以这题我们可以尝试使用00截断来绕过,如下:

然后直接访问shell.php,得到机密,题目解决
Lab:通过多语言 Web Shell 上传远程执行代码
题目中提到:尽管它会检查文件的内容以验证它是否是真正的图像,但仍然可以上传和执行服务器端代码。
说明后端会检查图片的内容,但是我们可以尝试做一个图片马
首先上传一张正常的图片,然后到bp的代理模块中的HTTP历史记录里面将显示图片的条目发送到重放器里面
接着在本机上面将一张图片和一份php代码文件合成图片马,如下:
命令(用cmd,在文件所在的目录):
1 | copy a.png /b + a.php /a 3.php |
注:这条命令的意思是:通过copy命令,把a.png图片文件,以二进制文件形式添加到a.php文件中,以ASCII文本文件形式输出为3.php文件。
接着将这份文件上传上去,并在bp中进行访问,得到我们所需要的机密,题目解决
借鉴
超详细文件上传漏洞总结分析:https://cloud.tencent.com/developer/article/1938541