前言:web安全之文件上傳漏洞,順帶講一下目錄遍歷攻擊。本文基於 java 寫了一個示例。
原理
在上網的過程中,我們經常會將一些如圖片、壓縮包之類的文件上傳到遠端服務器進行保存。文件上傳攻擊指的是惡意攻擊者利用一些站點沒有對文件的類型做很好的校驗,上傳了可執行的文件或者腳本,並且通過腳本獲得服務器上相應的權利,或者通過誘導外部用戶訪問、下載上傳的病毒或木馬文件,達到攻擊的目的。
文件上傳漏洞指攻擊者利用程序缺陷繞過系統對文件的驗證與處理策略將惡意程序上傳到服務器並獲得執行服務器端命令的能力。這種攻擊方式直接、有效,在對付某些脆弱的系統時甚至沒有門檻。
文件上傳漏洞的常見利用方式有:
上傳Web腳本程序,Web容器解釋執行上傳的惡意腳本。
上傳Flash跨域策略文件crossdomain.xml,修改訪問權限(其他策略文件利用方式類似)。
上傳病毒、木馬文件,誘騙用戶和管理員下載執行。
上傳包含腳本的圖片,某些瀏覽器的低級版本會執行該腳本,用於釣魚和欺詐。
總的來說,為了實現一次攻擊利用,必須要滿足以下條件:
文件能通過前端和后端的過濾和文件處理.
文件內容不會被改變,能夠被正確的存儲
存儲位置是在Web容器控制范圍
攻擊者有權限訪問存儲目錄
攻擊示例
基於 springmvc 的代碼
jsp 代碼
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="ctx" value="${pageContext.request.contextPath}" /> <html> <head> <title>web 安全之文件上傳漏洞</title> </head> <body> <form action="${ctx}/uploadFileDemoCtrl/uploadFile" method="post" enctype="multipart/form-data"> 選擇文件進行上傳:<input type="file" name="file"/> <input type="submit" value="上傳"/> </form> <br/> <form action="${ctx}/uploadFileDemoCtrl/downLoadFile" method="get"> 輸入需要下載的文件名稱:<input type="text" name="filename"/> <input type="submit" value="下載"/> </form> </body> </html>
java 代碼
controller 層 到jsp
@RequestMapping("/index") public String index(){ return "yule/uploadfile/uploadFileDemo"; }
上傳文件后台處理
/** * 文件上傳 * 有漏洞的上傳文件代碼 * @param request * @return * @throws IOException */ @RequestMapping("/uploadFile") public String uploadFile(HttpServletRequest request) throws IOException { // 轉型為MultipartHttpRequest MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; // 獲得文件到map容器中 Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); if(fileMap == null || fileMap.size() == 0){ System.out.println("沒有文件!"); return "yule/uploadfile/uploadFileDemo"; } String root = request.getServletContext().getRealPath("/upload"); File savePathFile = new File(root); if(!savePathFile.exists()){ savePathFile.mkdirs(); } String fileName = null; String suffixName = null; MultipartFile mf = null; InputStream fileIn = null; List<InputStream> isList = new ArrayList<InputStream>(); for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { mf = entity.getValue(); fileName = mf.getOriginalFilename();//獲取原文件名 suffixName = fileName.substring(fileName.lastIndexOf("."), fileName.length()); try { fileIn = mf.getInputStream(); isList.add(mf.getInputStream()); LocalFileUtils.upload(fileIn, root, fileName); } catch (IOException e) { e.printStackTrace(); }finally { if(fileIn != null){ fileIn.close(); } } } return "yule/uploadfile/uploadFileDemo"; }
運行,頁面如下:
上傳各種文件到工程下的 upload 文件夾下。
這里可以上傳各種文件,因為代碼沒有做任何的防止文件上傳漏洞的行為。這里代碼的漏洞非常容易被利用,比如,上傳一個有腳本的 jsp 文件 1.jsp,文件如下:
<%@page import="java.io.File"%> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String root = request.getServletContext().getRealPath("/upload"); out.write("系統部署文件上傳的絕對路徑:"+root); File file = new File(root); String[] tempList = file.list(); File temp = null; String fileName; for (int i = 0; i < tempList.length; i++) { if (root.endsWith(File.separator)) { fileName = root + tempList[i]; } else { fileName = root + File.separator + tempList[i]; } temp = new File(fileName); if (temp.isFile()) { out.write("刪除文件:" + fileName + ";"); temp.delete(); } } file.delete(); %>
上傳成功后,用地址訪問該文件,可怕的事情發生了,利用漏洞,會導致 upload 文件夾及下面的文件全部被刪除。
目錄遍歷攻擊
文件交互是一種簡單的過程,但是由於文件名可以任意更改而服務器支持“~/”,“../”等特殊符號的目錄回溯,從而使攻擊者越權訪問或者覆蓋敏感數據,如網站的配置文件、系統的核心文件,這樣的缺陷被命名為路徑遍歷漏洞
示例:
在 jsp 中加入 form 表單下載
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="ctx" value="${pageContext.request.contextPath}" /> <html> <head> <title>web 安全之文件上傳漏洞</title> </head> <body> <form action="${ctx}/uploadFileDemoCtrl/uploadFile" method="post" enctype="multipart/form-data"> 選擇文件進行上傳:<input type="file" name="file"/> <input type="submit" value="上傳"/> </form> <br/> <form action="${ctx}/uploadFileDemoCtrl/downLoadFile" method="get"> 輸入需要下載的文件名稱:<input type="text" name="filename"/> <input type="submit" value="下載"/> </form> </body> </html>
java 代碼
/** * 文件下載 * 有目錄遍歷攻擊漏洞的代碼 */ @RequestMapping("/downLoadFile") public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取項目部署絕對路徑下的upload文件夾路徑,下載upload目錄下面的文件 String root = request.getServletContext().getRealPath("/upload"); //獲取文件名 String filename = request.getParameter("filename"); File file = new File(root + "/" + filename); //根據文件路徑創建輸入流 FileInputStream fis = new FileInputStream(file); //設置響應頭,彈出下載框 response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes())); response.addHeader("Content-Length", "" + file.length()); byte[] b = new byte[fis.available()]; fis.read(b); response.getOutputStream().write(b); }
運行,頁面顯示如下:
在輸入框中輸入文件名,即可下載 upload 文件夾下的文件。但是這里如果輸入類似 “../WEB-INF/web.xml” 的文件名,則會下載 web.xml 文件,同理,很多文件都可以下載下來,包括一些配置文件,這就是目錄遍歷攻擊。
解決方案
這里可以通過數據庫存儲文件信息,下載利用數據庫 id 下載,同時后台傳給前端使用加密形式來防止這個漏洞。