admin管理员组文章数量:1637861
文件上传 原理 类型 预防
0x00 文件上传原理
文件上传漏洞是指用户上传了一个可执行脚本文件,并通过此文件获得了执行服务器端命令的能力。在大多数情况下,文件上传漏洞一般是指上传 WEB 脚本能够被服务器解析的问题,也就是所谓的 webshell 问题。完成这一攻击需要这样几个条件,一是上传的文件能够被 WEB 容器执行,其次用户能从 WEB 上访问这个文件,最后,如果上传的文件被安全检查、格式化、图片压缩等功能改变了内容,则可能导致攻击失败。
Webshell简介:
-
WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门。攻击者在入侵了一个网站后,通常会将这些asp或php后门文件与网站服务器web目录下正常的网页文件混在一起,然后使用浏览器来访问这些后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载或者修改文件,操作数据库,执行任意命令等)。
-
WebShell后门隐蔽较性高,可以轻松穿越防火墙,访问WebShell时不会留下系统日志,只会在网站的web日志中留下一些数据提交记录,没有经验的管理员不容易发现入侵痕迹。攻击者可以将WebShell隐藏在正常文件中并修改文件时间增强隐蔽性,也可以采用一些函数对WebShell进行编码或者拼接以规避检测。除此之外,通过一句话木马的小马来提交功能更强大的大马可以更容易通过
S出现场景:用户上传头像,编写文章上传图片等
PHP $_FILES函数
然后upload.php中可以直接用
$_FILES
$_POST
$_GET
等函数获取表单内容。
当客户端提交后,我们获得了一个$_FILES 数组
$_FILES数组内容如下:
$_FILES['myFile']['name'] 客户端文件的原名称。
$_FILES['myFile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
$_FILES['myFile']['size'] 已上传文件的大小,单位为字节。
$_FILES['myFile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir 指定,但 用 putenv() 函数设置是不起作用的。
$_FILES['myFile']['error'] 和该文件上传相关的错误代码。['error'] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在PHP3.0以后成了常量)
附加:本地upload环境搭建
0x01 为什么文件上传存在漏洞
- 上传文件的时候,如果服务器脚本语言,未对上传的文件进行严格的验证和过滤,就容易造成上传任意文件,包括上传脚本文件。
- 如果是正常的PHP文件,对服务器则没有任何危害。
- php可以像其他的编程语言一样,可以查看目录下的文件,查看文件中的吗内容,可以执行系统命令等。
- 上传文件的时候,如果服务器端脚本语言,未对上传的文件进行严格的验证和过滤,就有可能上传恶意的PHP文件,从而控制整个网站,甚至是服务器。这个恶意的PHP文件,又被称为WebShell。
0x02 客户端检测绕过(JS检测)
客户端检测绕过(javascript 检测)
-
简介
这类检测通常在上传页面里含有专门检测文件上传的 javascript 代码
最常见的就是检测扩展名是否合法
通常这种检测机制通常伴随页面 asp 弹框,检测流程是在本地的,不会上传流量到服务器
检测内容:
2.操作:前端对文件后缀进行检查,该种通过抓包修改数据包即可解决
绕过方法
- 我们直接删除代码中onsubmit事件中关于文件上传时验证上传文件的相关代码即可。
或者可以不加载所有js,还可以将html源码copy一份到本地,然后对相应代码进行修改,本地提交即可。
2.burp改包,由于是js验证,我们可以先将文件重命名为js允许的后缀名,在用burp发送数据包时候改成我们想要的后缀。
eg: CTF HUB web 前端验证
0x03服务端检测绕过 MIME 绕过
-
定义:MIME((Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式每个MIME类型由两部分组成,前面是数据的大类别,例如声音 audio、图象 Image等,后面定义具体的种类。
-
MIME类型就是服务端会检测Content-Type的值
-
Content-Type检测
HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型。不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改,不过加上一层防护也是可以有一定效果的。
-
常见的MME类型,例如:
-
超文本标记语言文本 .html,html text/htm
-
普通文本 .txt text/plain
-
RTF文本. rtf application/rtf
-
GIF图形 .gif image/gif
-
JPEG图形 . jpg image/jpeg
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nrIkCfWo-1611500711946)(C:\Users\77771\AppData\Roaming\Typora\typora-user-images\image-20210121231806868.png)]
-
- 检测原理
当用户上传文件到服务器端的时候,服务器端的程序会获取上传文件的MIME类型,然后用这个获取到的类型来和期望的MIME类型进行匹配,如果匹配不上则说明上传的文件不合法。服务端检测MIME类型的代码如下:
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')){
...//判断过后对文件处理的进一步操作
}
- 绕过方法
因为服务端检测的是文件的MIME类型,而对这个MIME类型的的值的获取是通过HTTP请求字段里的Content-Type字段 ,所以绕过的方法就是通过修改Content-Type的值,比如修改为image/jpeg;image/png;image/gif等等允许上传类型对应的MIME值
eg: CTF HUB web MIME绕过
0x04 服务端检测绕过(文件扩展名检测)
大致可以分为两类
- 黑名单后缀绕过
名单里有的后缀不可上传,上传没有的就行了
- 白名单后缀绕过
名单里有的后缀才可上传,如果是在前段验证可以加验证的后缀
0x01 00截断
-
定义:00截断是绕过上传限制的一种常见方法。在C语言中,“\0”是字符串的结束符,如果用户能够传入“\0”,就能够实现截断。
-
00截断通过上传限制适用的场景为,后端先获取用户上传的文件名,如x.php\00.jpg,再根据文件名获得文件的实际后缀jpg;通过后缀的白名单校验后,最后在保存文件时发生截断,实现上传的文件为x.php
-
0x00是十六进制表示方法,表示ASCII码为0的字符,在一些函数处理时,会把这个字符当作结束符。
0x00可以用在对文件名的绕过上,具体原理:系统在对文件名进行读取时,如果遇到0x00,就会认为读取已经结束。但要注意是文件的十六进制内容里的00,而不是文件名中的00。也就是说系统是按二进制或十六进制读取文件,遇到ASCII码为0的位置就停止,而这个ASCII码为0的位置在十六进制中是00。
总之就是利用ASCII码为0这个特殊字符,让系统认为字符串已经结束
-
注:php版本要 PHP<5.3.29,且GPC关闭
-
eg:upload labpass12
这题和上一题基本一样,只是
save_path
不在URL
中了,而在POST
数据里面,由于POST
里面的数据不会被url自动解码
,所以要稍微改变一下,首先,先改好路径,然后再路径后面加上一个字符,什么字符都可以,这里我为了方便用+
号。
然后再点击Hex
,找到对应+
的十六进制数据2b
。
直接双击2b
改为00
,再切回到RAW
,查看报文。
直接GO,查看返回结果。
访问,解析成功。
因为是十六进制所以这种截断叫做是0x00截断
,其实是%00截断
最终被url解码
还是会变成0x00
的。在url
中%00
表示ascll
码中的0
,而ascii
中0
作为特殊字符保留,表示字符串结束,所以当url
中出现%00
时就会认为读取已结束。这是一样的道理,所以这里还有另外一种做法。
直接在后面加上%00
然后选中,右键如下图进行url解码
即可,或者直接按ctrl+shfit+u
。
效果会是一样的。
源码不用分析什么,就是将GET
换成了POST
而已。$is_upload = false; $msg = null; if(isset($_POST['submit'])){ $ext_arr = array('jpg','png','gif'); $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); if(in_array($file_ext,$ext_arr)){ $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; //换成了POST if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true; } else { $msg = "上传失败"; } } else { $msg = "只允许上传.jpg|.png|.gif类型文件!"; } }
%00截断
- 原理:url发送到服务器后被服务器解码,这时还没有传到验证函数,也就是说验证函数里接收到的不是%00字符,而是%00解码后的内容,即解码成了0x00。总之就是%00被服务器解码为0x00发挥了截断作用。
- 例题 CTF hub web %00截断
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OuAPI4IJ-1611500711947)(C:\Users\77771\AppData\Roaming\Typora\typora-user-images\image-20210122234230481.png)]
0x0a截断
0x0a是十六进制表示方法,表示ASCII码为/n的换行字符,具体为换行至下一行行首起始位置。
分享一篇很好的00截断博客
http://www.admintony/%E5%85%B3%E4%BA%8E%E4%B8%8A%E4%BC%A0%E4%B8%AD%E7%9A%8400%E6%88%AA%E6%96%AD%E5%88%86%E6%9E%90.html
0x02 双写后缀绕过
- 原理:黑名单会给出一些不可使用的后缀名。
将写入一句话木马的php文件上传,抓包,将后缀改为.pphphp即可,双写即可绕过。
思路不唯一,各种后缀也是各种双写。 - 解析后,pphphp后缀名会变为php后缀名
eg: CTF HUB web 双写后缀名
0x03 后缀大小写绕过
eg: upload-labs Pass 6
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");
$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 . '文件夹不存在,请手工创建!';
}
}
我们发现对.htaccess也进行了检测,但是没有对大小写进行统一。
绕过原理:通过对检测不包含的后缀名(黑名单)漏洞利用来实现绕过
绕过方法
后缀名改为PHP即可//在实际操作中将后缀改为phP,pHp,Php等格式同样成立
0x04 空格绕过
eg: upload-labs Pass 7
源码分析
$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 = $_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
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;
本文标签: 文件上传
版权声明:本文标题:文件上传 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1729255568a1192621.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论