无回显的任意文件上传

简介: 无回显的任意文件上传

前言


在某次攻防中,遇到了cms站一个上传点,上传正常图片会回显路径,上传其他文件提示上传失败,且没有过多信息回显,一度以为没有漏洞。

通过找源码代码审计后getshell。


测试


在某次测试过程中发现,通过泄漏的md5进入后台,在后台配置中有处“上传logo”的功能。

通过一顿测试,上传文件为图片后缀但内容非图片(文件头),会提示“上传的不是一张图片”。

如果上传图片文件, 后缀改为php等  会提示“上传失败”。只有正常图片+图片后缀 会返回图片路径。

一时陷入僵局。

5e90c7f1486044842ac0318090ac31f2_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

7e9dc69779f3520a19b87224eb590ae4_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

一顿百度找到了源代码,那就从代码审计入手吧。


进行代码审计


首先找到上传点的入口文件。

635187b173a9e2719a373c37f6ccdad6_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

第一行 导入命名空间“phpWeChat” 内的 Upload 类,下面是引用包含一些文件。

再往下,$action是用于下面 switch函数内做索引匹配而调用不同功能的。

$action的值是通过 GET方式获取 “action”参数的值。如果空,就用预设的imageupload

当url为 :get:url/index.php?action=imageupload  进入到“imageupload”代码块

switch($action)  
{
  case 'imageupload':
    $originalname=preg_replace('/[^a-z0-9_]/i','',$originalname); 
    //过滤文件名特殊字符作用,i:不区分大小写模式
    $image=Upload::imageUpload($upload_file,$originalname);  
    //图片落地
    if(is_image($image)) { 省略}  //is_image() 获取文件后缀

其中核心的代码是$image 这一行。

通过使用命名空间中Upload类的imageUpload()方法获取并处理图片后落地,将结果返回。

返回的结果为在下一行if函数作为条件进行判断 。而具体做了什么先看imageUpload()函数做了什么,返回什么结果。

先看Upload类代码如下:

1eacb131a2c268b7345223741a4030f9_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

这里使用了命名空间,并在刚才的index.php文件内导入,来进行使用。

Upload类下,定义了几个静态方法,主要是图片、视频、压缩包上传,图片放大等方法

主要看下被调用的imageUpload()方法

dfe30fc463a68b8d737fa881a46e1920_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

在if中的表达式,通过文件上传变量  $_FILES 获取图片用此方法文件上传后,会被存储在服务器临时目录内,

上传成功后将满足if条件,进入if内代码。前四行依次获取上传的图片信息:文件名、临时路径、文件后缀、文件大小。

再经过两个if判断,判断是否post传入图片、判断文件是否超过限制大小。

到了209行这个关键点,会对文件进行检查。

971c7ea11c75743b8c77c6f0486c79b2_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

此处的if判断内使用了getimagesize()函数,并检查结果是否为数组,结果并取反

getimagesize()函数会文件头进行检查,来判断文件是否为有效的图片类型。并返回一个包含图片信息的数组。如果上传了非图片内容,getimagesize()返回 false

09ebd828d46b20267e242f42a3c369eb_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

所以上传非图片内容时,getimagesize()返回 false 并取反 此处会执行exit并弹框"上传的不是一张图片"

对该函数需要进行一个绕过

此时就需要一个图片马进行绕过。或是利用gif文件的头。

下面是一个正常的gif文件头。

b67e39ca5e4372f1e4aeff7c9052f66f_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。在GIF89a之前还有87a版(1987年5月发行)

可构造内容,进行绕过。


GIF89a<?php phpinfo();?>

条件满足后,代码往下执行。

8d9bb8be91d67cde791f7301d08da820_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

前两个变量分别赋值了,将要储存到的 文件名和 目录名

文件名取客户端提交时间+随机值,目录名取当前年月日,然后make_dir创建文件夹。

到了218行,if内表达式 使用move_uploaded_file将文件从tmp临时目录移动到网站上传目录内,此时文件已经写入硬盘目录move_uploaded_file执行成功后会返回 真值,进入if内进行图片文件尺寸放大等操作。

成功后,这时将返回一个文件路径结果

c1d21771d1cd7b99f36ffb8b84ddb211_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

再回到index入口文件。$image结果是imageUpload()方法返回的文件路径

9b037ca21a2725585eceff67b92c680b_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

$image在if判断的条件内,被is_image()处理。

eb53674f084447be8bfea6ff17e52818_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

is_image()通过获得后缀,然后在多个图片后缀数组内进行匹配,匹配到返回真值,否则 假。

如果不为'gif','jpg','jpeg','png','bmp'内后缀,结果为假的,前台将返回上传失败提示。

adbb510dfd66c7ca57bd052985a24ccc_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

但其实在服务器端,文件已经落地,返回任何信息也只是掩耳盗铃:

b398f9999c2b93a789a46696daaca18d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


总结


1.文件写入目录前,文件的后缀直接使用用户提交时的文件后缀,且未对后缀或文件类型进行检查。

2.文件落地后才进行后缀检查,这时的后缀检查完全是马后炮。

3.虽然对文件有有效性进行验证,但getimagesize()函数是可通过文件头(gif文件头)绕过。

4.move_uploaded_file()函数在php5部分版本中 可以使用 “%00”截断路径名,绕过后缀。

5.文件名前缀,是取客户端提交时间戳+四位随机数,文件名可以被枚举。

上述问题造成了任意文件上传漏洞。


相关文章
|
6天前
|
移动开发 前端开发
VForm3的文件上传后的一种文件回显方式
VForm3的文件上传后的一种文件回显方式
16 0
|
6天前
|
移动开发 前端开发
VForm3的文件上传方式
VForm3的文件上传方式
19 0
|
6天前
|
安全 网络安全
明御安全网关任意文件上传漏洞
安恒信息明御安全网关(以下简称“NGFW”)秉持安全可视、简单有效的理念,以资产为视角,构建“事前+事中+事后”全流程防御的下一代安全防护体系,并融合传统防火墙、入侵防御系统、防病毒网关、上网行为管控、VPN网关、威胁情报等安全模块于一体的智慧化安全网关。
123 1
|
6天前
文件上传地址的获取方法
文件上传地址的获取方法
22 1
|
5月前
文件上传 文件大小和类型
文件上传 文件大小和类型
|
8月前
|
监控 算法 Java
记一次从任意文件下载到getshell
记一次从任意文件下载到getshell
90 0
|
10月前
|
存储 Java
Java实现文件上传到本地(自定义保存路径)
Java实现文件上传到本地(自定义保存路径)
634 0
|
10月前
效验文件后缀及其流后缀 是否验证;文件大小
效验文件后缀及其流后缀 是否验证;文件大小
85 0
|
JSON 前端开发 JavaScript
上传文件返回数据提示下载
上传文件返回数据提示下载