不安全的文件下载和上传
不安全的文件下载
文件下载(unsafedownload)漏洞概述
很多网站都会提供文件下载功能,即用户可以通过点击下载链接,下载到链接所对应的文件。
但是,如果文件下载功能设计不当,则可能会导致攻击者可以通过构造文件路径,从而获取到后台服务器上的其他的敏感文件。
文件下载功能在很多web系统上都会出现,一般我们当点击下载链接,便会向后台发送一个下载请求,一般这个请求会包含一个需要下载的文件名称,后台在收到请求后 会开始执行下载代码,将该文件名对应的文件response给浏览器,从而完成下载。 如果后台在收到请求的文件名后,将其直接拼进下载文件的路径中而不对其进行安全判断的话,则可能会引发不安全的文件下载漏洞。
此时如果 攻击者提交的不是一个程序预期的的文件名,而是一个精心构造的路径(比如…/…/…/etc/passwd),则很有可能会直接将该指定的文件下载下来。 从而导致后台敏感信息(密码文件、源代码等)被下载。
所以,在设计文件下载功能时,如果下载的目标文件是由前端传进来的,则一定要对传进来的文件进行安全考虑。 切记:所有与前端交互的数据都是不安全的,不能掉以轻心!
靶场
![image-20221212162110385](https://i-blog.csdnimg.cn/blog_migrate/b4ef594134ac2e377ddd3c97a01352d9.png)
我们右键名字,新标签页中打开链接,可以发现自动将图片下载了,我们从URL里可以看到请求,它其实就是把kb.png这么一个filename传到了后台,后台就去找这个文件,把这个文件读取后,又响应到前端,浏览器就可以把它下载下来了这么一个过程。如果说后端的代码控制不够严格,这个地方很有可能就出现漏洞了。
一般来说测试这种文件下载漏洞呢,我们可以通过目录遍历的方式
![image-20221212163701311](https://i-blog.csdnimg.cn/blog_migrate/1b74ef80d65a8f3f7bad46e352f5a642.png)
主要我们输入足够多的…/你其实是可以跳转到根目录下的,然后我们可以以根目录为起点往下去做相关的读取
比如这样:
我们就会把hosts文件下载下来了
这个其实就是后端对我们传入进去的文件名对应的文件进行读取的时候它的控制不够严格,就导致了恶意文件下载这么一个漏洞
我们来看一下后台源码:
![image-20221212164332236](https://i-blog.csdnimg.cn/blog_migrate/9a9ed5aa82f8642edb3726e62ede4588.png)
![image-20221212164433577](https://i-blog.csdnimg.cn/blog_migrate/d2d60c86a8837868e33bed9adbc7c834.png)
这里最根本的原因就是它对前端传进来的文件没有做任何判断。它不会对这个文件判断是不是它目录下的就对它进行读取。当前端传进来一个文件名,它应该对这个文件名进行校验,判断这个文件名是否在被下载的文件范围内,不在就告诉文件不存在,在的话就下载,这样才不会有问题。
防范措施
- 对传入的文件名进行严格的过滤和限定;
- 对文件下载的目录进行严格的规定;
不安全的文件上传
文件上传(unsafeupload)漏洞解析
因为业务功能需要,很多web站点都有文件上传的接口,比如:
- 注册时上传头像图片(比如jpg,png,gif等);
- 上传文件附件(doc,xls等);
而在后台开发时并没有对上传的文件功能进行安全考虑或者采用了有缺陷的措施,导致攻击者可以通过一些手段绕过安全措施从而上传一些恶意文件(如:一句话木马)。从而通过对该恶意文件的访问来控制整个web后台。
文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行重命名后存储在指定的目录。 如果说后台对上传的文件没有进行任何的安全判断或者判断条件不够严谨,则攻击着可能会上传一些恶意的文件,比如一句话木马,从而导致后台服务器被webshell。
所以,在设计文件上传功能时,一定要对传进来的文件进行严格的安全考虑。比如:
- 验证文件类型、后缀名、大小;
- 验证文件的上传方式;
- 对文件进行一定复杂的重命名;
- 不要暴露文件上传后的路径;
- 等等…
文件上传漏洞测试流程
- 对文件上传的地方按照要求上传文件,查看返回结果(路径,提示等);
- 尝试上传不同类型的恶意文件,比如xx.php文件,分析结果;
- 查看html源码,看是否通过js在前端做了上传限制,可以绕过;
- 尝试使用不同方式进行绕过:黑白名单绕过/MIME类型绕过/目录0x00截断绕过等;
- 猜测或结合其他漏洞(比如敏感信息泄露等)得到木马路径,连接测试;
客户端验证
![image-20221212170115112](https://i-blog.csdnimg.cn/blog_migrate/4c5bfaec80963dc8baa9967d7043ec6b.png)
我们尝试上传一个php文件
![image-20221212170303019](https://i-blog.csdnimg.cn/blog_migrate/825e6244e887051b89d9d0dd7e6c40b6.png)
出现一个弹窗说我们上传的文件不符合要求,这里是一个前端的JS弹窗,他直接通过前端弹出了一个框,那么我们就会怀疑它是不是通过前端做的限制呢?我们来看一下
我们打开开发者选项,查看器查看源码
![image-20221212170512264](https://i-blog.csdnimg.cn/blog_migrate/a2154896a1e5d55294ece66d5dab7051.png)
我们在这里查看浏览按钮,可以看出这里有一个对应的判断,当input标签去onchange,发生改变的时候,他就回去调用checkFileExt
我们右键页面去看一下源码
![image-20221212170741875](https://i-blog.csdnimg.cn/blog_migrate/025d03506576f245406014512017bc52.png)
checkFileExt这个函数就是通过JavaScript来判断上传的内容来进行相关的限制,所有在前端做的限制只能起到辅助的作用,起不到实际性的作用。比如说我们可以通过控制台对代码进行修改,比如说我们可以把checkFileExt函数删掉,这和我们之前XSS漏洞的时候修改限制字数一样。
![image-20221212171059900](https://i-blog.csdnimg.cn/blog_migrate/7bed71c6a275b2614afa91511877a0af.png)
删掉以后我们再上传,就不会有那样的限制了。
![image-20221212171602201](https://i-blog.csdnimg.cn/blog_migrate/acddf0ef6be781de0bb5b1cefe6a46df.png)
我们上传的这个a1.php里面其实就是一个一句话木马
![image-20221212171524204](https://i-blog.csdnimg.cn/blog_migrate/1c2310530906cb37a16e0b6b889e427e.png)
我们可以来试一下
![image-20221212171723175](https://i-blog.csdnimg.cn/blog_migrate/0a2ae6903aa41a57d4c598afc78e3e8f.png)
![image-20221212172121444](https://i-blog.csdnimg.cn/blog_migrate/7e371a8aff9dbdcbdec0d1bd5a89b02a.png)
这样就可以直接被执行了,我们在这里就是绕过了客户端的限制,上传了一个非预期的文件。通过对这个一句话木马的访问,我们就能控制整个服务器。
服务端验证
文件上传漏洞之MIME类型
MIIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩 展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。常见的MIME类型,比如:
- 超文本标记语言文本.html,.html texthtml
- 普通文本.txt text/plain
- RTF文本.rtf application/rtf
- GIF图形.gif image/gif
- JPEG图形.ipeg,jpg image/jpeg
$_FILES()函数
通过使用PHP的全局数组$_FILES,你可以从客户计算机向远程服务器上传文件。第一个参数是表单的input name,第二个下标可以是“name”,“type”,“size”,“tmp_name”或”error“。就像这样:
- $_FILES[“file”] [“name”] - 被上传文件的名称
- $_FILES[“file”] [“type”] - 被上传文件的类型
- $_FILES[“file”] [“size”] - 被上传文件的大小。以字节计
- $_FILES[“file”] [“tmp_name”] - 存储在服务器的文件的临时副本的名称
- $_FILES[“file”] [“error”] - 由文件上传导致的错误代码
验证
![image-20221213090235757](https://i-blog.csdnimg.cn/blog_migrate/d5ea48794944baadbfef03e67f062ca4.png)
我们还是首先验证一下正常功能,我们上传一张正常的照片看看
![image-20221213090655404](https://i-blog.csdnimg.cn/blog_migrate/e0bbae3eafec10fa167dc82db76740d3.png)
![image-20221213090709716](https://i-blog.csdnimg.cn/blog_migrate/7076d136d144cb3548e82c2c47c026e5.png)
没有问题,这个是可以正常上传成功的。我们可以试一下php文件
![image-20221213090811179](https://i-blog.csdnimg.cn/blog_migrate/9d02dce1856a893a3787785bf99a624c.png)
我们可以看到上传失败了,提示我们上传的文件不是图片格式。我们直接先来看一下源码
关键点在于它定义了一个$_FILES去获取文件的类型,然后再把这个类型去和他定义好的mime type去进行比较。
我们首先上传一个正常的图片,去抓一下它的content-type,然后我们再去上传一下我们的一句话木马
我们先看我们上传成功的图片,他这里的Content-Type是image/png
![image-20221213091831908](https://i-blog.csdnimg.cn/blog_migrate/b470cddb798ec98db35c4400539bbd5a.png)
我们再来看一下我们上传失败的php文件,他这里的Content-Type是被认为了application/octet-stream
![image-20221213091945678](https://i-blog.csdnimg.cn/blog_migrate/439231a082f0b4898eb357f795b73c77.png)
我们可以把这个数据包发送到Repeter里面去,然后我们复制一下上面上传成功的Content-Type,我们可以在Repeter里面把这个Content-Type替换掉
![image-20221213092247628](https://i-blog.csdnimg.cn/blog_migrate/585725d6e8852655933b0e89133914f6.png)
我们点击发送,查看返回结果
![image-20221213092425734](https://i-blog.csdnimg.cn/blog_migrate/71ce6840c9d0b4a2e2f762d2bfa26d1c.png)
我们可以看到文件上传成功,那这样就说明我们通过对HTTP头的修改,绕过了后端的MIME的限制。这个PHP文件上传成功后,就和前面的一样,我们可以通过访问这个PHP文件,传参,通过一句话木马来控制服务器。
文件上传漏洞之getmagesize()类型验证
Getimagesize()返回结果中有文件大小和文件类型,如果用这个函数来获取类型,从而判断是否是图片的话,会存在问题。
是否可以绕过呢?可以,因为图片头可以被伪造。
![image-20221213093551457](https://i-blog.csdnimg.cn/blog_migrate/9ad53d4c7748d29bc45e89d129606d66.png)
我们上传正常图片是可以的。我们就可以尝试上传一张带有恶意代码的图片,也就是图片马。
图片木马的制作:
-
方法一:直接伪造头部GIF89A
-
方法二:CMD:copy /b test.png+muma.php cccc.png
其中b表示以二进制文件,a表示以ASCII文件
-
方法三:使用GIMP(开源的图片修改软件),增加备注,写入执行命令
![image-20221213095005312](https://i-blog.csdnimg.cn/blog_migrate/8386b38d7572bce0601271117697c7b2.png)
![image-20221213095447241](https://i-blog.csdnimg.cn/blog_migrate/75f528365458f681f4674b8ddfbd0a9b.png)
![image-20221213095509718](https://i-blog.csdnimg.cn/blog_migrate/4ab7a8ce68238ff287b5f0a854216178.png)
我们可以用C32Asm来看一下这张生成好的图片的十六进制
![image-20221213095910920](https://i-blog.csdnimg.cn/blog_migrate/7fdea04ef7ec95cf6c7ef0d221499c6b.png)
我们可以看到这章图片前面都是原来的图片十六进制内容,但是最后接入了我们刚才输入的php内容
![image-20221213100601852](https://i-blog.csdnimg.cn/blog_migrate/13b903bcb6ec2fa7fcc182e2a41c591d.png)
我们可以看到此时的这张图片马就可以被我们成功上传了,意味着这个点是存在文件上传漏洞的。Getimagesize()是可以被绕过,它只是对文件十六进制的开头进行一个判断。
即使绕过也仅仅是说你可以上传一个带有恶意代码的图片,但是这个图片的恶意代码你只有执行,才能达到一个利用的效果,我们直接访问这个图片,实际上这个恶意代码是不会被执行的。
![image-20221213100955242](https://i-blog.csdnimg.cn/blog_migrate/bb6fefa5c0cc775dc7c2c265a530ecc6.png)
我们得到一张图片,也可以看到我们的php并没有被执行
这时候我们可以通过文件包含漏洞来利用这个图片木马,因为include函数会包含上传的文件执行任意代码,我们可以利用它的这个漏洞执行木马。
在本地文件包含中,选择一项点击提交,把URL中的filename的值修改为图片木马的路径。
../../unsafeupload/uploads/2022/12/13/4940776397ddef38b6e823906942.png
出现下面这样的页面就说明我们返回对了
![image-20221213101622534](https://i-blog.csdnimg.cn/blog_migrate/8617769e578fd640f0ff062ca759b077.png)
我们可以滑倒最下面看到我们的phpinfo被执行了
这样就相当于通过一个本地文件包含加上一个图片验证不够严格的图片上传问题,进行一个结合性的使用,实现出一个更深层次的危害。
防范措施
- 不要在前端使用JS实施上传限制策略
- 通过服务端对上传文件进行限制:
- 进行多条件组合检查:比如文件的大小、路径、扩展名、文件类型、文件完整性
- 对上传的文件在服务器上存储时进行重命名(制定合理的命名规则)
hpinfo被执行了
[外链图片转存中…(img-dtq51cJ0-1670925366918)]
这样就相当于通过一个本地文件包含加上一个图片验证不够严格的图片上传问题,进行一个结合性的使用,实现出一个更深层次的危害。
防范措施
- 不要在前端使用JS实施上传限制策略
- 通过服务端对上传文件进行限制:
- 进行多条件组合检查:比如文件的大小、路径、扩展名、文件类型、文件完整性
- 对上传的文件在服务器上存储时进行重命名(制定合理的命名规则)
- 对服务器端上传文件的目录进行权限控制(比如只读) ,,限制执行权限带来的危害