<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    文件訪問類漏洞

    文件訪問類漏洞

    本章節將講解與Java文件或目錄訪問安全性問題,常見的Java文件操作相關的漏洞大致有如下類型:

    1. 任意目錄遍歷

    2. 任意文件、目錄復制

    3. 任意文件讀取/下載

    4. 任意文件、目錄修改/重命名

    5. 任意文件、目錄刪除

    6. ……

    我們通常把這類漏洞歸為一個類型,因為產生漏洞的原因都是因為程序對文件或目錄訪問控制不嚴、程序內部邏輯錯誤導致的任意文件或目錄惡意訪問漏洞。

    1. 任意文件讀取

    任意文件讀寫漏洞即因為沒有驗證請求的資源文件是否合法導致的,此類漏洞在Java中有著較高的幾率出現,任意文件讀取漏洞原理很簡單,但一些知名的中間件:WeblogicTomcatResin又或者是主流MVC框架:Spring MVCStruts2都存在此類漏洞。

    示例 - 存在惡意文件讀取漏洞代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <%@ page import="java.io.FileInputStream" %>
    
    <pre>
    
    <%
    
        File file = new File(request.getRealPath("/") + request.getParameter("name"));
    
        FileInputStream in = new FileInputStream(file);
    
        int tempbyte;
    
        while ((tempbyte = in.read()) != -1) {
    
            out.write(tempbyte);
    
        }
    
        in.close();
    
    %>
    
    </pre>
    

    1.1 同級目錄任意文件讀取漏洞測試

    攻擊者通過傳入惡意的name參數可以讀取服務器中的任意文件:http://localhost:8000/modules/filesystem/FileInputStream.jsp?name=./index.jsp,如下圖:

    文件訪問類漏洞

    1.2 讀取WEB-INF/web.xml測試

    當攻擊者通過傳入惡意的name參數值為WEB-INF/web.xml時可以讀取Web應用的配置信息,請求:http://localhost:8000/modules/filesystem/FileInputStream.jsp?name=WEB-INF/web.xml,如下圖:

    文件訪問類漏洞

    1.3 跨目錄讀取敏感文件測試

    開發人員通常使用文件名、文件后綴、文件目錄進行拼接的方式來獲取待操作文件的絕對路徑并進行相關操作,在這種情況下,攻擊者如果想要查看服務器中的其他目錄,則會使用 ../ 進行目錄的跨越,常使用的操作是跨越目錄到服務根目錄,再向下尋找文件。例如../../../../../../../../etc/passwd

    請求:http://localhost:8000/modules/filesystem/FileInputStream.jsp?name=../../../../../../../../../../../../etc/passwd,如下圖:

    文件訪問類漏洞

    2. 寫文件

    示例 - 存在惡意文件寫入漏洞的代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <%@ page import="java.io.FileOutputStream" %>
    
    <%
    
        File file = new File(request.getParameter("f"));
    
        FileOutputStream fos = new FileOutputStream(file);
    
        fos.write(request.getParameter("c").getBytes());
    
        fos.flush();
    
        fos.close();
    
        out.println(file.getAbsoluteFile() + "\t" + file.exists());
    
    %>
    

    2.1 跨目錄寫入文件測試

    攻擊者可能期望跨目錄寫入文件,如寫入 SSH KEY、寫入計劃任務等等方式進行進一步的攻擊。

    請求:http://localhost:8000/modules/filesystem/file-w.jsp?f=../../a.rar&c=aaa,如下圖:

    文件訪問類漏洞

    2.2 絕對路徑寫入文件測試

    攻擊者通過傳入惡意的參數fc參數可以使用絕對路徑在服務器上寫入惡意的WebShell后門或其他文件,請求:http://localhost:8000/modules/filesystem/file-w.jsp?f=/tmp/2.txt&c=webshell,如下圖:

    文件訪問類漏洞

    3. 刪除文件

    3.1 任意文件刪除測試

    示例 - 存在任意文件刪除漏洞代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <%
    
        File file = new File(request.getParameter("file"));
    
        out.println(file.delete());
    
    %>
    

    攻擊者通過參入file參數即可刪除服務器中的任意文件:

    文件訪問類漏洞

    3.2 FileSystem任意文件刪除測試

    示例 - 存在任意文件刪除漏洞代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <%@ page import="java.lang.reflect.Method" %>
    
    <%
    
        String file = request.getParameter("file");
    
        Method m = Class.forName("java.io.DefaultFileSystem").getMethod("getFileSystem");
    
        m.setAccessible(true);
    
        Object fs = m.invoke(null);
    
        Method m2 = fs.getClass().getMethod("delete", File.class);
    
        m2.setAccessible(true);
    
        out.print(m2.invoke(fs, new File(file)));
    
    %>
    

    攻擊者通過參入file參數即可刪除服務器中的任意文件:

    文件訪問類漏洞

    攻擊者通過反射調用 Filesystem 并執行delete方法,用來繞過對 File 對象 delete方法的防御。

    4. 文件/目錄復制、移動

    示例 - 存在任意文件復制漏洞代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.IOException" %>
    
    <%@ page import="java.nio.file.Files" %>
    
    <%@ page import="java.nio.file.Path" %>
    
    <%@ page import="java.nio.file.Paths" %>
    
    <pre>
    
    <%
    
        try {
    
            Path path = Files.copy(Paths.get(request.getParameter("source")), Paths.get(request.getParameter("dest")));
    
            out.println(path);
    
        } catch (IOException e) {
    
            e.printStackTrace();
    
        }
    
    %>
    
    </pre>
    

    攻擊者傳入惡意的sourcedest參數可以實現復制任何文件到任意的目錄,比如攻擊者可以在用戶中心上傳一張內容為WebShell惡意代碼的1.jpg圖片文件,然后通過漏洞將1.jpg圖片文件,復制到同級目錄并更新名稱為1.jsp的可解析腳本文件,訪問1.jsp文件即可實現控制服務器的目的,如下圖:

    文件訪問類漏洞

    在實際環境中,應用系統可能根據需求在配置文件如web.xml中或代碼層面如filter設置某些目錄(如上傳目錄、資源目錄等)禁止對 .jsp 腳本文件等可執行文件進行解析,因此,攻擊者需要將惡意文件移動或復制到其他能夠執行的目錄進行解析。請求:http://localhost:8000/modules/filesystem/files-copy.jsp?source=/tmp/1.jsp&dest=/Users/yz/Desktop/apache-tomcat-8.5.31/webapps/ROOT/1.jsp,如下圖:

    文件訪問類漏洞

    5. 重命名文件

    示例 - 存在文件名重命名漏洞代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <%
    
        String fileName1 = request.getParameter("s");
    
        String fileName2 = request.getParameter("d");
    
        File f = new File(fileName1);
    
        File d = new File(fileName2);
    
        f.renameTo(d);
    
        out.println(d + "\t" + d.exists());
    
    %>
    

    攻擊者傳入惡意的sd參數即可將文件名為1.txt的文本文件重命名為1.jsp可執行腳本文件,請求:http://localhost:8000/modules/filesystem/file-rename.jsp?s=/tmp/1.txt&d=/tmp/1.jsp,如下圖:

    文件訪問類漏洞

    攻擊者會使用重命名的方式將(txt、jpg等資源文件)重命名為可執行腳本文件(jsp)來獲得webshell從而控制Web應用系統,并繞過某些安全防護機制。常見的攻擊手段是在文件上傳時,上傳包含惡意代碼的圖片文件,再利用重命名將其轉為可執行的腳本文件。

    6. 文件目錄遍歷

    任意目錄遍歷漏洞顧名思義攻擊者可以通過漏洞遍歷出服務器操作系統中的任意目錄文件名,從而導致服務器敏感信息泄漏,某些場景下(如遍歷出網站日志、備份文件、管理后臺等)甚至可能會導致服務器被非法入侵。

    示例 - 存在任意目錄遍歷代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.File" %>
    
    <pre>
    
    <%
    
        String[] files = new File(request.getParameter("dir")).list();
    
        for (String file : files) {
    
            out.println(file);
    
        }
    
    %>
    
    </pre>
    

    這個漏洞可能由Web應用本身的開發不規范導致,也有可能是因為MVC框架項目依賴的第三方庫Web服務器自身導致的。如果是由于自身開發不規范導致的那么需要程序嚴格控制用戶傳入目錄參數是否合法!

    6.1 相對目錄遍歷測試

    攻擊者傳入dir參數即可遍歷出對應目錄的所有文件,http://localhost:8000/modules/filesystem/file-list.jsp?dir=../,如下圖:

    文件訪問類漏洞

    由于攻擊者傳入的dir參數值為相對路徑,可能是多級目錄名稱,也可能只是一個非常簡單的../上級目錄,大部分的WAF并不能精準識別這類攻擊。

    6.2 絕對目錄遍歷測試

    當攻擊者可以傳入絕對路徑進行攻擊時,路徑中將不會存在../等穿越目錄特征,很多WAF將無法攻擊阻攔,請求:http://localhost:8000/modules/filesystem/file-list.jsp?dir=/etc,如下圖:

    文件訪問類漏洞

    7. IO和NIO.2的文件系統支持

    7.1 使用NIO任意文件讀取漏洞測試

    示例 - 存在任意文件讀取的NIO.2代碼:

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%@ page import="java.io.IOException" %>
    
    <%@ page import="java.nio.file.Files" %>
    
    <%@ page import="java.nio.file.Paths" %>
    
    <pre>
    
    <%
    
        try {
    
            byte[] bytes = Files.readAllBytes(Paths.get(request.getParameter("file")));
    
            out.println(new String(bytes));
    
        } catch (IOException e) {
    
            e.printStackTrace();
    
        }
    
    %>
    
    </pre>
    

    攻擊者傳入惡意的file即可讀取服務器中的任意文件:

    文件訪問類漏洞

    8. 任意文件/目錄訪問漏洞修復

    8.1 限制讀取目錄或文件

    在讀取文件或者目錄的時候我們需要考慮到文件讀取安全問題,嚴格控制用戶傳入參數,禁止或限制用戶傳入文件路徑。

    檢測用戶參數合法性代碼示例(請根據具體業務需求調整判定邏輯):

    
    <%@ page import="java.io.File" %><%--
    
      Created by IntelliJ IDEA.
    
      User: yz
    
      Date: 2019/12/4
    
      Time: 6:08 下午
    
      To change this template use File | Settings | File Templates.
    
    --%>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <%!
    
        // 定義限制用戶遍歷的文件目錄常量
    
        private static final String IMAGE_DIR = "/data/images/";
    
    %>
    
    <%
    
        // 定義需要遍歷的目錄
    
        String dirStr = request.getParameter("dir");
    
        if (dirStr != null) {
    
            File dir = new File(dirStr);
    
            // 獲取文件絕對路徑,轉換成標準的文件路徑
    
            String fileDir = (dir.getAbsoluteFile().getCanonicalFile() + "/").replace("\\\\", "/").replaceAll("/+", "/");
    
            out.println("<h3>" + fileDir + "</h3>");
    
            // 檢查當前用戶傳入的目錄是否包含在系統限定的目錄下
    
            if (fileDir.startsWith(IMAGE_DIR)) {
    
                File[] dirs = dir.listFiles();
    
                out.println("<pre>");
    
                for (File file : dirs) {
    
                    out.println(file.getName());
    
                }
    
                out.println("</pre>");
    
            } else {
    
                out.println("目錄不合法!");
    
            }
    
        }
    
    %>
    

    請求遍歷非系統限制的目錄示例:

    文件訪問類漏洞

    8.2 RASP防御惡意文件訪問攻擊

    RASP可以使用Agent機制實現Hook任意的Java類API,因此可以輕易的捕獲到Java程序讀取的任意文件路徑。RASP可以將Hook到的文件路徑和Http請求的參數進行關聯分析,檢測Java讀取的文件路徑是否會受到Http請求參數的控制,如果發現請求參數最終拼接到了文件路徑中應當立即阻斷文件訪問行為,并記錄攻擊日志。

    為了提升RASP的防御能力,應當將Java SE中的所有與文件讀寫相關的最為底層的Java API類找出來,然后添加監視點。

    Java底層操作IO的類API表(<=JDK14)

    | 類名 | 類型 | 重要方法 |

    | ———————————— | ——— | ———————————————————— |

    | java.io.WinNTFileSystem | java.io | delete/list/createDirectory/rename/setLastModifiedTime/listRoots |

    | java.io.UnixFileSystem | java.io | delete/list/createDirectory/rename/setLastModifiedTime/listRoots |

    | java.io.FileInputStream | java.io | open/read |

    | java.io.FileOutputStream | java.io | open/write |

    | java.io.RandomAccessFile | java.io | read/write/seek |

    | sun.nio.ch.FileChannelImpl | sun.nio | open/read/map/transferTo0 |

    | sun.nio.ch.FileDispatcher | sun.nio | read/pread/readv/write/pwrite/writev/seek |

    | sun.nio.ch.SocketDispatcher | sun.nio | read/readv/write/writev |

    | sun.nio.ch.DatagramDispatcher | sun.nio | read/readv/write/writev |

    | sun.nio.fs.UnixNativeDispatcher | sun.nio | fopen/read/write/getcwd/link/unlink/rename/mkdir/chown |

    | sun.nio.fs.WindowsNativeDispatcher | sun.nio | fopen/read/write/getcwd/link/unlink/rename/mkdir/chown |

    | sun.nio.fs.UnixCopyFile | sun.nio | copy/copyDirectory/copyFile/move/copyLink/copySpecial/transfer |

    | sun.nio.ch.IOUtil | sun.nio | read/write/randomBytes |

    Java IO 底層API關系圖

    文件訪問類漏洞

    RASP防御思路:

    文件訪問類漏洞

    當RASP檢測到惡意的文件訪問后會立即阻斷文件讀取:

    文件訪問類漏洞

    8.2.1 禁止文件名空字節訪問

    在低版本的JDK中允許文件名中包含空字節(俗稱%00截斷),為了防止該問題,RASP應當在任何文件被訪問的時候檢測文件名是否包含了空字節,如果有應當立即終止文件的訪問。

    檢測文件名空字節示例代碼:

    
    /**
    
     * 檢查文件名中是否包含了空字節,禁止出現%00字符截斷
    
     *
    
     * @param file 訪問文件
    
     * @return 是否包含空字節
    
     */
    
    private static boolean nullByteValid(File file) {
    
       return file.getName().indexOf('\u0000') < 1;
    
    }
    

    8.2.2 禁止寫入動態腳本文件

    為了避免Web應用被寫入惡意的WebShell后門文件,RASP應當在Web應用啟動后禁止任何動態腳本的寫入操作。在任何與寫入文件相關的Java底層方法執行前都應當檢測寫入的文件后綴是否合法。

    禁止寫入如下類型的動態腳本文件:

    jsp,jspx,jspa,jspf,asp,asa,cer,aspx,php

    文件寫入檢測應當處理各類文件寫入事件,如:寫文件、重命名文件、復制/移動文件、移動目錄;RASP設置Hook點時也應當嚴格處理上述IO操作的類文件(一個都不能漏掉,漏掉一個幾乎等于全功盡棄),如果新版本的JDK新增或修改了底層IO操作類應當做同步支持。

    8.2.3 文件名和請求參數關聯分析

    RASP應當分析Hook到的文件路徑和請求參數的關聯性,分析每一個參數是否對最終Hook到的文件路徑有必然的關聯關系。

    如傳入的某個參數最終和Hook到的文件路徑完全一致,那么應當立即禁止文件訪問請求,因為即便用戶請求的不是惡意文件也肯定是一個存在任意文件讀取漏洞的業務功能,攻擊者可以修改傳入的參數實現讀取服務器中的任意文件。

    8.2.4 文件名檢測規則和黑名單

    攻擊者在驗證文件讀取類漏洞時通常會使用一些常用的技巧和路徑,如:WEB-INF/web.xml/etc/passwd../../../../../../../etc/passwd等。RASP應該有一些內置的黑名單和檢測規則來防止黑客攻擊。

    9. Java 惡意文件訪問審計建議

    在審計文件讀取功能的時候要非常仔細,或許很容易就會有意想不到的收獲!快速發現這類漏洞得方式其實也是非常簡單的,在IDEA中的項目中重點搜下如下文件讀取的類。

    1. JDK原始的java.io.FileInputStreamjava.io.FileOutputStream

    2. JDK原始的java.io.RandomAccessFile

    3. Apache Commons IO提供的org.apache.commons.io.FileUtils

    4. JDK1.7新增的基于NIO非阻塞異步讀取文件的java.nio.channels.AsynchronousFileChannel類;

    5. JDK1.7新增的基于NIO讀取文件的java.nio.file.Files類。常用方法如:Files.readAllBytesFiles.readAllLines

    6. java.io.File類的listlistFileslistRootsdelete方法;

    除此之外,還可以搜索一下FileUtil/FileUtils很有可能用戶會封裝文件操作的工具類。

    10. Java 惡意文件訪問總結

    首先,在Java中任意文件或目錄惡意訪問漏洞是一種非常常見的高危漏洞!多是因為程序內部邏輯錯誤或者過于信任用戶傳入的參數導致的。其次此類漏洞原理簡單在滲透測試或代碼審計時非常容易發現且漏洞影響重大,因為攻擊者可以直接操縱服務器中的文件或目錄,所以在程序開發過程中我們應該高度重視編碼規范、程序邏輯嚴謹性防止該漏洞發生。

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类