最近項目的測試哥們提了一個linux系統軟鏈接攻擊的問題,項目中導出服務器上某個文件的時,通過軟連接漏洞可以獲取到其他文件的信息。
具體過程自己寫了個下載的Demo模擬了一下:
下載的servlet和html如下,下載/opt/temp/a.txt,國際慣例,內容是hello world,文件大小12kb。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Download File</title> <script type="text/javascript"> function download() { window.open("download.do"); } </script> </head> <body> <input type="button" value="Download" onclick="download()" /> </body> </html>

package com.dj.servlet; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.util.http.fileupload.IOUtils; /** * @author DU * */ @WebServlet("/download.do") public class DownloadDemoServlet extends HttpServlet { private static final long serialVersionUID = 1L; public DownloadDemoServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = "a.txt"; response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); String filePath = "/opt/temp/" + fileName; FileInputStream is = new FileInputStream(new File(filePath)); ServletOutputStream os = response.getOutputStream(); IOUtils.copy(is, os); os.close(); is.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
這樣下載下來的文件沒有任何問題,接下來就涉及軟鏈接的問題,在服務器上/home目錄下有一個npp.7.3.3.Installer.x64.exe的文件,當然這是個notepad++的安裝文件,我自己放進去的。先將/opt/temp/a.txt刪除掉,然后用xshell執行命令ln -s /home/npp.7.3.3.Installer.x64.exe /opt/temp/a.txt 創建.exe的軟鏈接文件為a.txt,關於軟鏈接文件這里不細表,可以自行百度,可以理解為類似windows的快捷方式,創建成功之后是這樣的,注意這時候文件大小已經是2.84M了。
然后再次點擊下載,這個時候下載下來的是這樣的:
是的,下載軟鏈接會直接下載軟鏈接指向的源文件,如果是敏感文件的話就很不好了。當然,筆者依然處於菜鳥階段,還不是很清楚惡意攻擊者可以通過怎樣的手段達到創建出這個軟鏈接。
接下來就是如何規避這個問題了:
第一種方式是通過對比文件的絕對路徑和規整化路徑,如果是源文件的話這兩個路徑應該是一樣的,否則就是鏈接文件。

// 對比絕對路徑和規整化路徑 String absolutePath = file.getAbsolutePath(); String canonicalPath = file.getCanonicalPath(); if (!absolutePath.equals(canonicalPath)) { response.getWriter().append("Download Failed!"); return; }
第二種方式可以直接通過jdk1.7開始出現的java.nio.file.Files類提供的接口判斷。

// 直接通過java.nio.file包中提供的接口判斷 Path path = Paths.get(filePath); boolean isSymbolicLink = Files.isSymbolicLink(path); if (isSymbolicLink) { response.getWriter().append("Download Failed!"); return; }
如圖,校驗成功!