无回显的任意文件上传

无回显的任意文件上传


前言

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

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


测试

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

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

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

一时陷入僵局。

无回显的任意文件上传

无回显的任意文件上传

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


进行代码审计

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

无回显的任意文件上传

第一行 导入命名空间“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类代码如下:

无回显的任意文件上传

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

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

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

无回显的任意文件上传

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

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

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

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

无回显的任意文件上传

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

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

无回显的任意文件上传

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

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

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

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

无回显的任意文件上传

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

可构造内容,进行绕过。

GIF89a<?php phpinfo();?>

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

无回显的任意文件上传

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

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

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

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

无回显的任意文件上传

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

无回显的任意文件上传

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

无回显的任意文件上传

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

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

无回显的任意文件上传

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

无回显的任意文件上传

总结

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

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

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

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

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

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


往期回顾

01

frida hook native层巧解Android逆向题

02

看老外谈信息收集



03

webshell免杀之函数与变量玩法


无回显的任意文件上传

雷石安全实验室

商务咨询:

0571-87031601

商务邮箱:

mtn@motanni.com


原文始发于微信公众号(雷石安全实验室):无回显的任意文件上传

版权声明:admin 发表于 2022年11月25日 下午5:01。
转载请注明:无回显的任意文件上传 | CTF导航

相关文章

暂无评论

暂无评论...