1 普通文件上传功能实现
新建1个aspx文件,在form里添加如下代码:
<asp:FileUpload ID="fileupload1" runat="server" />
<asp:Button ID="btnUpload" Text="Upload" runat="server" OnClick="btnUpload_Click" />
后台编写如下代码:
protected void btnUpload_Click(object sender, EventArgs e) { string filePath = Server.MapPath("./Upload/") + fileupload1.FileName; fileupload1.SaveAs(filePath); }
基本上传功能就搞定了。
2 漏洞演示
先准备一个aspx文件,里面只有1行:
<%=DateTime.Now %>
我们用浏览器上传这个文件,到服务器目录一看,文件已上传成功了。
现在请求如下地址:
http://localhost/Test/Upload/Test.aspx
可以看到,这个ASPX文件已经被IIS执行了,和我们写的aspx文件没有区别。
如果这个文件包含恶意代码,服务器将被攻击。
3 原理总结
这个漏洞的主要原因只有1个,上传的文件被iis当成ASPX文件执行了。
如果iis不执行,将什么问题也没有,为什么iis执行了这个文件呢?有2点:
第一:文件在网站的目录下。
第二:文件的扩展名为aspx,是iis可执行的文件名。
符合这2点,用户发出请求,iis就去执行了。
4 解决方案
很多文章谈到此漏洞时,都大谈特谈怎么控制用户传上来的文件,有文件名检查啦,有文件内容验证了,有抓包工具了,等等,在此我想说,为什么不考虑下第一点?为什么把文件放在这个网站的目录下面呢?如果第一点不满足,即便是aspx文件又怎么样呢,是exe文件又怎么样呢?
上传文件的需求是传上去后要使用,上传文件存盘的目录直接挂在网站目录下,用户传上去就立刻能用了,简单方便。这样做有漏洞,怎么办呢?最简单的方法就是:
在IIS 里对上传目录 配置不执行任何脚本和扩展。这样即便传上来的aspx文件也不会被执行。
另外一点,就是文件存盘时的路径直接定死,直接等于 指定的目录 + uuid,不要有任何使用外部变量的运算在里面,比如取传上来的文件名,比如取客户的Id,等等,不给攻击者任何把文件传到其他目录的机会。 简单粗暴直接有效。
附:
1 我们没有编写上传功能,会有这个漏洞吗?
是否用了其他有上传功能的第三方组件呢?比如ckEditor,如果有,请把它们存盘的目录的权限设定一下。
2 我们使用的AjaxUpload上传,是无刷新上传,也有这个漏洞吗?
重点不是前端使用什么技术,重点是传上来的文件是否可以被IIS执行!我们的设定目的也是让上传上来的文件不能被执行。
如果使用的不是IIS,是其他编程语言的环境,一样按此思路处理,都能收到事半功倍的效果。