【文件上传漏洞04】服务端MIME检测与绕过实验(基于upload-labs-2靶场)-爱代码爱编程
1 MIME概述
1.1 概述
- 定义:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,是描述消息内容类型的因特尔标准。MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。
- 意义:MIME设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。
1.2 文件格式
每个MIME类型由两部分组成,前面是数据的大类别,video、image、application、text、audio、multipart、message等,后面定义具体的种类。常见的MIME类型(通用型)如下表,更多类型请百度。
文件类型 | 后缀名 | MIME |
---|---|---|
超文本标记语言文本 | .html | text/html |
xml文档 | .xml | text/xml |
普通文本 | .txt | text/plain |
PDF文档 | application/pdf | |
Microsoft Word文件 | .word | application/msword |
PNG图像 | .png | image/png |
GIF图形 | .gif | image/gif |
JPEG图形 | .jpeg,.jpg | image/jpeg |
au声音文件 | .au | audio/basic |
MIDI音乐文件 | .mid, .midi | audio/midi, audio/x-midi |
RealAudio音乐文件 | .ra, .ram | audio/x-pn-realaudio |
MPEG文件 | .mpg,.mpeg | video/mpeg |
AVI文件 | .avi | video/x-msvideo |
GZIP文件 | .gz | application/x-gzip |
TAR文件 | .tar | application/x-tar |
1.3 检测与绕过
如果服务端代码是通过Content-Type的值来判断文件的类型,那么就存在被绕过的可能,因为Content-Type的值是通过客户端传递的,是可以任意修改的 。
2 实验简介
2.1 实验目的
掌握绕过MIME检测的方法,验证文件上传漏洞的存在。
2.2 实验环境
- 靶场:基于WAMP环境的upload-labs靶场,搭建过程可参考文章《基于WAMP环境的upload-labs漏洞测试平台搭建过程》。
- 攻击机:安装BurpSuite软件。
2.3 实验前准备
- 准备好一个文件,该文件可能是木马,也可能是其他任意文件,本实验以php探针作为测试文件,来验证是否存在文件上传漏洞以及绕过漏洞检测的方法。
- 文件名为:
info.php
,文件内容:<?php phpinfo();?>
。
3 实验过程
- 打开BurpSuite,在代理模块打开其自带浏览器。
- 浏览器访问靶机,并打开第二关。点击选择文件,选择准备好的info.php,点击上传出现以下错误提示。
- 查看源代码,判断是否存在JS检测。在52~56行,可以看到表单中有事件检测,但是没有找打对应的函数,应该是没有JS检测的。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="icon" type="image/x-icon" href="/upload-labs/img/favicon.png" />
<title>upload-labs</title>
</head>
<link rel="stylesheet" type="text/css" href="/upload-labs/css/index.css">
<link rel="stylesheet" type="text/css" href="/upload-labs/css/prism.css">
<body>
<div id="head">
<a href="/upload-labs/"><img src="/upload-labs/img/logo.png"/></a>
<div id="head_menu">
<a id="handle_code" href="javascript:show_code()">显示源码</a>
<a href="javascript:get_prompt()">查看提示</a>
<a href="javascript:clean_upload_file()">清空上传文件</a>
</div>
</div>
<div id="main"><div id="menu">
<ul id="menulist">
<li><a id="Pass-01" href="/upload-labs/Pass-01/index.php">Pass-01</a></li>
<li><a id="Pass-02" href="/upload-labs/Pass-02/index.php">Pass-02</a></li>
<li><a id="Pass-03" href="/upload-labs/Pass-03/index.php">Pass-03</a></li>
<li><a id="Pass-04" href="/upload-labs/Pass-04/index.php">Pass-04</a></li>
<li><a id="Pass-05" href="/upload-labs/Pass-05/index.php">Pass-05</a></li>
<li><a id="Pass-06" href="/upload-labs/Pass-06/index.php">Pass-06</a></li>
<li><a id="Pass-07" href="/upload-labs/Pass-07/index.php">Pass-07</a></li>
<li><a id="Pass-08" href="/upload-labs/Pass-08/index.php">Pass-08</a></li>
<li><a id="Pass-09" href="/upload-labs/Pass-09/index.php">Pass-09</a></li>
<li><a id="Pass-10" href="/upload-labs/Pass-10/index.php">Pass-10</a></li>
<li><a id="Pass-11" href="/upload-labs/Pass-11/index.php">Pass-11</a></li>
<li><a id="Pass-12" href="/upload-labs/Pass-12/index.php">Pass-12</a></li>
<li><a id="Pass-13" href="/upload-labs/Pass-13/index.php">Pass-13</a></li>
<li><a id="Pass-14" href="/upload-labs/Pass-14/index.php">Pass-14</a></li>
<li><a id="Pass-15" href="/upload-labs/Pass-15/index.php">Pass-15</a></li>
<li><a id="Pass-16" href="/upload-labs/Pass-16/index.php">Pass-16</a></li>
<li><a id="Pass-17" href="/upload-labs/Pass-17/index.php">Pass-17</a></li>
<li><a id="Pass-18" href="/upload-labs/Pass-18/index.php">Pass-18</a></li>
<li><a id="Pass-19" href="/upload-labs/Pass-19/index.php">Pass-19</a></li>
<li><a id="Pass-20" href="/upload-labs/Pass-20/index.php">Pass-20</a></li>
<li><a id="Pass-21" href="/upload-labs/Pass-21/index.php">Pass-21</a></li>
</ul>
</div>
<div id="upload_panel">
<ol>
<li>
<h3>任务</h3>
<p>上传一个<code>webshell</code>到服务器。</p>
</li>
<li>
<h3>上传区</h3>
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="上传"/>
</form>
<div id="msg">
提示:文件类型不正确,请重新上传! </div>
<div id="img">
</div>
</li>
</ol>
</div>
</div>
<div id="footer">
<center>Copyright @ <span id="copyright_time"></span> by <a href="http://gv7.me" target="_bank">c0ny1</a></center>
</div>
<div class="mask"></div>
<div class="dialog">
<div class="dialog-title">提 示<a href="javascript:void(0)" class="close" title="关闭">关闭</a></div>
<div class="dialog-content"></div>
</div>
</body>
<script type="text/javascript" src="/upload-labs/js/jquery.min.js"></script>
<script type="text/javascript" src="/upload-labs/js/prism.js"></script>
<script type="text/javascript" src="/upload-labs/js/prism-line-numbers.min.js"></script>
<script type="text/javascript" src="/upload-labs/js/prism-php.min.js"></script>
<script type="text/javascript" src="/upload-labs/js/index.js"></script>
</html>
- BurpSuite开启代理拦截功能,网页选择info.php文件,点击上传,可以看到BurpSuite成功拦截到请求,这意味着网页上JS并没有检测文件后缀名。在拦截的请求中,将Content-Type修改为image/png,点击forward,后续请求无需修改直接点击forward。
- 可以看到请求发送成功,并收到后端的响应显示如下,由于该文件不是真的图片,因此显示失败。
- 鼠标右键上图中红框位置(本该是显示图片的位置),点击“新建标签页打开”,可以看到在新的页面成功执行该文件,并返回探针信息内容。如果是其他页面语句,也将成功执行。
4 总结
- 测试思路:前端JS→服务器端MIME类型。
- 掌握MIME绕过方法。