查看原文
其他

一次Web探测服务器技术学习总结

随风而行aa 看雪学苑 2022-07-01


本文为看雪论坛精华文章

看雪论坛作者ID:随风而行aa




简介


最近有一个学习需求,获取域名相应服务器的标题、服务器名、服务器语言、服务器版本等基本信息,为此开始了相关方面的学习和开发,下面是学习过程,本文分为三个部分:
 
本文第二节讲解本次项目的基本背景知识。
 
本文第三节主要为项目实践,代码开发过程。
 
本文第四节主要介绍一些网络上常见的Web探测的一些方案,并介绍一个自动化的信息获取框架,并完成复现过程。



基础知识


完成一个服务器的基本信息获取,仅仅需要简单的Java HTTP编程知识、Java正则匹配式知识即可。


1、HTTP网络编程


(1)HTTP简介


HTTP是一种超文本传输协议,是基于TCP协议之上的一种请求-响应请求协议。
 
浏览器访问某个网站时发送的HTTP请求-响应,当浏览器希望访问某个网站时,浏览器和网站服务器之间先建立TCP连接,且服务器总是使用80端口和加密端口443,然后浏览器向服务器发送一个HTTP请求,服务器收到之后,返回一个HTTP响应,响应中包含了HTML的网页内容,浏览器解析HTML后就给用户显示网页,详细流程图如下所示:
<1> HTTP请求

HTTP请求的格式是固定的,由HTTP Header和HTTP Body两部分组成。

第一行:请求方法 路径 HTTP版本  例如,GET / HTTP/1.1 表示使用GET请求,路径是/,版本是HTTP/1.1。

后续各行的每一行是固定的Header:Value格式,我们称为HTTP Header,服务器依靠某些特定的Header来识别客服端请求。

Host:表示请求的域名。

User-Agent:表示客户端自身标识信息,不同的浏览器有不同的标识,服务器依靠User-Agent判断客户端类型是IE还是Chrome,是Firefox还是一个Python爬虫。

Accept:表示客户端能处理的HTTP响应格式,*/*表示任意格式,text/*表示任意文本,image/png表示PNG格式的图片。

Accept-Language:表示客户端接收的语言,多种语言按优先级排序,服务器依靠该字段给用户返回特定语言的网页版本。


Get请求和Post请求:
 
如果是Get请求,那么该HTTP请求只有HTTP Header,没有HTTP Body。
 
如果是POST请求,那么该HTTP请求带有Body,以一个空行分隔,一个典型的带Body的HTTP请求如下:
POST /login HTTP/1.1Host: www.example.comContent-Type: application/x-www-form-urlencodedContent-Length: 30 username=hello&password=123456

POST请求通常要设置Content-Type表示Body的类型,Content-Length表示Body的长度,这样服务器可以根据请求的Header和Body做出正确的响应。
 
GET请求的参数必须附加在URL上,并以URLEncode方式编码,例如:http://www.example.com/?a=1&b=K%26R,参数分别是a=1和b=K&R,因为URL的长度限制,GET请求的参数不能太多,POST请求的参数就没有长度限制,POST请求的参数必须放在Body中,POST请求的参数不一定是URL编码,可以按任意1格式编码,只需要在Content-Type中正确设置即可。发送JSON的POST请求:
POST /login HTTP/1.1Content-Type: application/jsonContent-Length: 38 {"username":"bob","password":"123456"}

<2> HTTP响应

HTTP响应也是由Header和Body两部分组成,一个典型的HTTP响应如下:
HTTP/1.1 200 OKContent-Type: text/htmlContent-Length: 133251 <!DOCTYPE html><html><body><h1>Hello</h1>...

响应的第一行是 HTTP版本 响应代码 响应说明
1xx:表示一个提示性响应,例如101表示将切换协议,常见于WebSocket连接;2xx:表示一个成功的响应,例如200表示成功,206表示只发送了部分内容;3xx:表示一个重定向的响应,例如301表示永久重定向,303表示客户端应该按指定路径重新发送请求;4xx:表示一个因为客户端问题导致的错误响应,例如400表示因为Content-Type等各种原因导致的无效请求,404表示指定的路径不存在;5xx:表示一个因为服务器问题导致的错误响应,例如500表示服务器内部故障,503表示服务器暂时无法响应。

当浏览器收到第一个HTTP响应后,它解析HTML,又会发送一系列HTTP请求,例如,GET /logo.jpg HTTP/1.1请求一个图片,服务器响应图片请求后,会直接把二进制内容图片发送给浏览器。
HTTP/1.1 200 OKContent-Type: image/jpegContent-Length: 18391 ????JFIFHH??XExifMM?i&??X?...(二进制的JPEG图片)

因此服务器总是被动地接收客户端的一个HTTP请求,然后响应它,客户端则根据需求发送若干个HTTP请求。
 
HTTP 1.0 是每次发送一个HTTP请求,客户端都需要先建立一个新的TCP连接,收到服务器响应后,关闭这个TCP连接。
 
HTTP 1.1协议允许在一个TCP连接中反复发送——响应,这样能大大提升效率。
 
HTTP 2.0 允许客户端在没有收到响应的时候,发送多个HTTP请求,服务器返回响应的时候,不一定按顺序返回,只要双方识别出哪个响应对应哪个请求,就可以做到并行发送和接收。


(2)HTTP编程


HTTP客户端编程:
URL url = new URL("http://www.example.com/path/to/target?a=1&b=2");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setUseCaches(false);conn.setConnectTimeout(5000); // 请求超时5秒// 设置HTTP头:conn.setRequestProperty("Accept", "*/*");conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 11; Windows NT 5.1)");// 连接并发送HTTP请求:conn.connect();// 判断HTTP响应是否200:if (conn.getResponseCode() != 200) { throw new RuntimeException("bad response");} // 获取所有响应Header:Map<String, List<String>> map = conn.getHeaderFields();for (String key : map.keySet()) { System.out.println(key + ": " + map.get(key));}// 获取响应内容:BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line = reader.readLine();while(line != null){...}

JAVA 11开始引入新的HttpClient,使用链式调用的API,能大大简化HTTP的处理。
 
首先需要创建一个全局HttpClient实例,因为HttpClient内部使用线程池优化多个HTTP连接,可以复用:
static HttpClient httpClient = HttpClient.newBuilder().build();

使用GET请求获取文本内容:
import java.net.URI;import java.net.http.*;import java.net.http.HttpClient.Version;import java.time.Duration;import java.util.*; public class Main { // 全局HttpClient: static HttpClient httpClient = HttpClient.newBuilder().build(); public static void main(String[] args) throws Exception { String url = "https://www.sina.com.cn/"; HttpRequest request = HttpRequest.newBuilder(new URI(url)) // 设置Header: .header("User-Agent", "Java HttpClient").header("Accept", "*/*") // 设置超时: .timeout(Duration.ofSeconds(5)) // 设置版本: .version(Version.HTTP_2).build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // HTTP允许重复的Header,因此一个Header可对应多个Value: Map<String, List<String>> headers = response.headers().map(); for (String header : headers.keySet()) { System.out.println(header + ": " + headers.get(header).get(0)); } System.out.println(response.body().substring(0, 1024) + "..."); }}

要使用POST请求,我们要准备好发送的Body数据并正确设置Content-Type:
String url = "http://www.example.com/login";String body = "username=bob&password=123456";HttpRequest request = HttpRequest.newBuilder(new URI(url)) // 设置Header: .header("Accept", "*/*") .header("Content-Type", "application/x-www-form-urlencoded") // 设置超时: .timeout(Duration.ofSeconds(5)) // 设置版本: .version(Version.HTTP_2) // 使用POST并设置Body: .POST(BodyPublishers.ofString(body, StandardCharsets.UTF_8)).build();HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());String s = response.body();


2、Curl 工具的使用


(1)Curl基本命令


<1> 查看网页源码
curl www.baidu.comcurl -o [文件名] www.baidu.com //使用-o参数,相当于使用wget命令

<2>自动跳转
curl -L www.baidu.com

这个主要解决一些网址多级别重定向的设置。

<3>显示头信息
curl -i www.baidu.com //获取响应头的信息curl --trace output.txt www.baidu.com //使用trace可以获取更加详细的信息

<4>显示通信过程
curl -v www.baidu.com-v参数可以显示一次http通信的整个过程,包括端口连接和http request头信息

<5>发送表单信息
curl example.com/form.cgi?data=xxx //GET方法相对简单,只要把数据附在网址后面就行curl -X POST --data "data=xxx" example.com/form.cgi //POST方法必须把数据和网址分开,curl就要用到--data参数

<6>User Agent字段
这个字段是用来表示客户端的设备信息。服务器有时会根据这个字段,针对不同设备,返回不同格式的网页 curl --user-agent "[User Agent]" [URL] //也可以用 -A 来替代--user-agent

这里我们就介绍下本文需要用到的一些字段,更详细的可以去参考下面的链接。
 
Curl 学习参考链接:

https://www.ruanyifeng.com/blog/2019/09/curl-reference.html

https://www.ruanyifeng.com/blog/2011/09/curl.html

https://cizixs.com/2014/05/14/curl-automate-http/


(2)Curl Java代码使用

/* * 功能说明 * Curl指令的java代码 * 输入函数:curl指令 * 返回参数:curl指令的返回值 * 例子:curl [option] [url] * curl url //获取url的html * curl -A "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0)" url //使用指定的浏览器去访问 * curl -I url //返回header信息 * */ public static String execCurl(String[] cmds,String chartname) { ProcessBuilder process = new ProcessBuilder(cmds); Process p; try { p = process.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(),chartname)); StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(line); builder.append(System.getProperty("line.separator")); } return builder.toString(); } catch (IOException e) { System.out.print("error"); e.printStackTrace(); } return null; }


String[] cmds = {"curl","-A","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36","-L","-i",domain}; String result_html = execCurl(cmds,charset);




项目模块代码


我们开始编写获取服务器的项目工程,我们可以在IDEA上新建一个项目工程。


1、对象类

public class WebInfo { public String domain = ""; public String ip = ""; public String title=""; public String http_server = ""; public String http_server_version = ""; public String language = ""; public String set_Cookie = ""; public String X_Powered_By = ""; //服务器加密的状态 public Boolean isServerCrypto = false; public String charset = ""; public WebInfo(){} public String toString(){ String str = ""; str = str + this.domain + "\t"; str = str + this.ip + "\t"; str = str + this.title + "\t"; str = str + this.http_server + "\t"; str = str + this.http_server_version + "\t"; str = str + this.language + "\t"; return str; } public boolean checkComplete() { return this.title != null && this.title.length() > 0 && this.http_server != null && this.http_server.length() > 0 && this.language != null && this.language.length() > 0; }


2、功能函数


(1)服务器信息获取函数

//使用curl获取服务器信息,输入url public static void getServerInfo(WebInfo wi,String domain) throws IOException { String charset = "utf-8"; charset = getCharset(domain); //System.out.println("charset:"+charset); if(!matcherChar(charset,"gb")){ charset = "utf-8"; } //-L 跟随跳转 -i 打印详细信息 String[] cmds = {"curl","-A","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36","-L","-i",domain}; String result_html = execCurl(cmds,charset); //获取的header和html信息 //System.out.println(result_html); if(!result_html.isEmpty()){ wi.title = getTitle(result_html); }else{ System.out.println("无法获取域名的html"); } strName(wi,result_html); LanguageCheck(wi); NormalLanguageTest(wi); ExceptionCheck(wi); // CheckStatus(wi); }


/* * 功能说明 * Curl指令的java代码 * 输入函数:curl指令 * 返回参数:curl指令的返回值 * 例子:curl [option] [url] * curl url //获取url的html * curl -A "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0)" url //使用指定的浏览器去访问 * curl -I url //返回header信息 * */ public static String execCurl(String[] cmds,String chartname) { ProcessBuilder process = new ProcessBuilder(cmds); Process p; try { p = process.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(),chartname)); StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(line); builder.append(System.getProperty("line.separator")); } return builder.toString(); } catch (IOException e) { System.out.print("error"); e.printStackTrace(); } return null; }


(2)标题获取函数

/* * 函数说明: * getTitle(String webcontent): * 输入参数:web页面信息html * 返回结果:标题 * */ public static String getTitle(String webContent){ Pattern pattern = Pattern.compile("<title>.*?</title>",Pattern.CASE_INSENSITIVE|Pattern.DOTALL); Matcher ma =pattern.matcher(webContent); while (ma.find()){ //System.out.println(ma.group()); return outTag(ma.group()); } return null; }


//去除标题中的一些无关信息 public static String outTag(String s) { String title = s.replaceAll("<.*?>", ""); title=replaceBlank(title); title = title.replace("首页", ""); title = title.replace("-", ""); title = title.replace("主页", ""); title = title.replace("官网", ""); title = title.replace("欢迎进入", ""); title = title.replace("欢迎访问", ""); title = title.replace("登录入口", ""); return title; }


//除去标题字符串中的\t制表符 \n回车 \r换行符 public static String replaceBlank(String str) { String dest = ""; if (str!=null) { Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll(""); } return dest; }


(3)获取url编码格式

public static String getCharset(String link) { String charset = "utf-8"; HttpURLConnection conn = null; try { URL url = new URL(link); conn = (HttpURLConnection)url.openConnection(); conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"); conn.connect(); System.setProperty("sun.net.client.defaultConnectTimeout","30000"); System.setProperty("sun.net.client.defaultReadTimeout", "30000"); String contentType = conn.getContentType(); //在header里面找charset charset = findCharset(contentType); //System.out.println("header:"+charset); //如果没找到的话,则一行一行的读入页面的html代码,从html代码中寻找 if(charset.isEmpty()){ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = reader.readLine(); while(line != null) { if(line.contains("Content-Type")) { // result = findCharset(line); Pattern p = Pattern.compile("content=\"text/html;\\s*charset=([^>]*)\""); Matcher m = p.matcher(line); if (m.find()) { charset = m.group(1); System.out.println("html:"+charset); } break; } line = reader.readLine(); } reader.close(); } } catch (Exception e) {// TODO Auto-generated catch block //这里可以打印响应不了的域名错误信息 //e.printStackTrace(); } finally { conn.disconnect(); } return charset; }


//获取charsetpublic static String findCharset(String line){ String charset = ""; if(line.contains("charset")){ String[] arr=line.split("=",2); for(String str:arr){ if(!str.equals("charset")){ charset = str; } } return charset; }else { return ""; } }


(4)正则匹配式

/* * 正则表达式匹配:输入字符串、正则表达式 * 例如:reg3 = "Server:\\s(\\D*)(\\s|\/)(.*)"; * 返回匹配的结果数组 * */ public static String[] RegCheck(String str,String reg){ String[] result=new String[4]; String[] resultnew = {}; Pattern p = Pattern.compile(reg); Matcher m = p.matcher(str); if (m.matches()) { for(int i=0;i<=m.groupCount();i++){ result[i]=m.group(i); //System.out.println("result[i]:"+result[i]); //System.out.println("m.group(i):"+m.group(i)); } return result; }else { return resultnew; } }


//匹配字符串,不区分大小写,参数:源字符串,匹配的字符串public static Boolean matcherChar(String strName,String matChar){ Pattern pattern =Pattern.compile(matChar, Pattern.CASE_INSENSITIVE); Matcher matcher=pattern.matcher(strName); return matcher.find();}


(5)服务器版本和服务器名获取


细粒度获取:
/* * 匹配包头信息和服务器html信息,获取服务器名和服务器版本 * */ public static void strName(WebInfo wi,String strcontent) throws IOException { if(!strcontent.isEmpty()){ BufferedReader br =new BufferedReader(new InputStreamReader(new ByteArrayInputStream(strcontent.getBytes(Charset.forName("utf-8"))))); String line; String[] items; StringBuffer strbuf = new StringBuffer(); while ((line = br.readLine())!=null){ String reg = "Server:\\s(\\D*)(\\s|\\/|\\*)(.*)"; String reg1 = "Server:\\s(\\D*)"; String[] result =RegCheck(line,reg); if(result.length>0){ //System.out.println("result.length:"+result.length); wi.http_server = result[1]; wi.http_server_version = result[3]; if(wi.http_server==null){ wi.http_server=""; } if(wi.http_server.contains("*")){ wi.http_server = ""; wi.isServerCrypto = true; } } if(line.contains("Set-Cookie")){ String[] arr=line.split(":",2); for(String str:arr){ if(!str.equals("Set-Cookie")){ wi.set_Cookie = str; } } } if(line.contains("X-Powered-By")){ String[] arr=line.split(":",2); for(String str:arr){ if(!str.equals("X-Powered-By")){ wi.X_Powered_By= str; } } }// //检测主体中的服务器版本信息 if (matcherChar(line, "Apache")&&wi.http_server.isEmpty()){ wi.http_server = "Apache"; } if (matcherChar(line, "Nginx")&&wi.http_server.isEmpty()){ wi.http_server = "Nginx"; } if (matcherChar(line, "Lighttpd ")&&wi.http_server.isEmpty()){ wi.http_server = "Lighttpd"; } if (matcherChar(line, "IIS ")&&wi.http_server.isEmpty()){ wi.http_server = "IIS "; } if (matcherChar(line, "WebSphere")&&wi.http_server.isEmpty()){ wi.http_server = "WebSphere"; } if (matcherChar(line, "Weblogic")&&wi.http_server.isEmpty()){ wi.http_server = "WebSphere"; } if (matcherChar(line, "Boa")&&wi.http_server.isEmpty()){ wi.http_server = "Boa"; } if (matcherChar(line, "Jigsaw")&&wi.http_server.isEmpty()){ wi.http_server = "Jigsaw"; } } if(wi.http_server.isEmpty()){ marcherServer(wi,strcontent); } br.close(); } }

版本顺序识别:
/* 处理加密服务器,无法获得版本 * 匹配服务器顺序,根据主流服务器的响应头顺序来识别 * 例如:Apache 顺序:Http->Date->Server */ public static void marcherServer(WebInfo wi,String strcontent) throws IOException { if(!strcontent.isEmpty()) { BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(strcontent.getBytes(Charset.forName("utf-8"))))); String line; int i=0; StringBuffer strbuf = new StringBuffer(); while ((line = br.readLine()) != null) { i=i+1; if(line.contains("HTTP")&&i==1){ // i=2; } if(line.contains("Date")&&i==2){ wi.http_server="Apache"; break; } if(line.contains("Server")&&i==2){ //i=3; } if(line.contains("Expires")&&i==3){ wi.http_server="IIS"; break; } if(line.contains("Data")&&i==3){ //i=4; } if(line.contains("Content-Type")&&i==4){ wi.http_server="Enterprise "; break; } if(line.contains("Content-length")&&i==4){ wi.http_server="SunONE"; break; } if(i==5){ break; } } } }


(6)服务器语言获取


细粒度获取:
//用于检测服务器语言的指纹信息,输入参数:webInfo对象 public static void LanguageCheck(WebInfo wi) { if(wi.set_Cookie.contains("PHPSSIONID")&&wi.language.isEmpty()){ wi.language = "PHP"; } if(wi.set_Cookie.contains("JSESSIONID")&&wi.language.isEmpty()){ wi.language = "JAVA"; } if(wi.X_Powered_By.contains("ASP.NET")||wi.set_Cookie.contains("ASPSESS")||wi.set_Cookie.contains("ASP.NET")&&wi.language.isEmpty()){ wi.language = "ASP.NET"; if(wi.http_server.isEmpty()){ wi.http_server = "IIS"; } } if(wi.X_Powered_By.contains("JBoss")&&wi.language.isEmpty()){ wi.language = "JAVA"; if(wi.http_server.isEmpty()){ wi.http_server = "JBOSS"; } } if(wi.X_Powered_By.contains("Servlet")&&wi.language.isEmpty()){ wi.language = "JAVA"; if(wi.http_server.isEmpty()){ wi.http_server = "SERVLET"; } } if(wi.X_Powered_By.contains("Next.js")&&wi.language.isEmpty()){ wi.language = "NODEJS"; } if(wi.X_Powered_By.contains("Express")&&wi.language.isEmpty()){ wi.language = "NODEJS"; } if(wi.X_Powered_By.contains("Dragonfly CMS")&&wi.language.isEmpty()){ wi.language = "PHP"; } if(wi.X_Powered_By.contains("PHP")&&wi.language.isEmpty()){ wi.language = "PHP"; } if(wi.X_Powered_By.startsWith("JSF")&&wi.language.isEmpty()){ wi.language = "JAVA"; if(wi.http_server.isEmpty()){ wi.http_server = "SERVLET"; } } if(wi.X_Powered_By.startsWith("WP")&&wi.language.isEmpty()){ wi.language = "PHP"; } if(wi.X_Powered_By.startsWith("enduro")&&wi.language.isEmpty()){ wi.language = "NODEJS"; } }

粗粒度获取:
/* * 服务器版本语言检测,如果语言指纹信息仍然检测不到,针对加密服务器,采用一般检测方式,误差率较高 * */ public static void NormalLanguageTest(WebInfo wi){ if(!wi.http_server.isEmpty()){ if (wi.http_server.contains("IIS") && wi.language.isEmpty()) { wi.language = "ASP.NET"; } if (wi.http_server.contains("Tomcat")||wi.http_server.contains("Resin")|| wi.http_server.contains("JBoss")&& wi.language.isEmpty()) { wi.language = "Java"; } if (wi.http_server.contains("Nginx") && wi.language.isEmpty()) { wi.language = "Python"; } if (wi.http_server.contains("Apache")&&wi.language.isEmpty()) { wi.language = "PHP"; } if (wi.http_server.contains("VWebServer")||wi.http_server.contains("Enterprise")&&wi.language.isEmpty()) { wi.language = "JAVA"; } if (wi.http_server.contains("nginx")&&wi.language.isEmpty()) { wi.language = "C"; } if (wi.http_server.contains("Oracle-HTTP-Server")&&wi.language.isEmpty()){ wi.language = "Java|C|Perl|PHP"; } if (wi.http_server.contains("openresty")&&wi.language.isEmpty()){ wi.language = "Lua|C"; } if (wi.http_server.contains("GWS")&&wi.language.isEmpty()){ wi.language = "C++"; } } }


3、测试函数

public static void main(String[] args) throws IOException { WebInfo wi = new WebInfo(); getServerInfo(wi,"http://js.jxedu.gov.cn"); System.out.println("title:"+wi.title+"\nhttp_server:"+wi.http_server+"\nlanguage:"+wi.language+"\nhttp_server_version:"+wi.http_server_version+"\nisServerCrypto:"+wi.isServerCrypto); System.out.println("---------------------"); }

测试结果显示:




服务器信息探测框架


上文我们初步实现了一个基本的服务器信息获取的项目,经过调研,我总结了一下目前网上的一些常用的方案,并复现了一个自动化的框架。


1、网站自动化识别语言框架


这里我总结调研了网络上常用的一些网站语言测试框架,并总结如下:


2、W11scan工具的使用


这里介绍github上一位老哥开源的框架,使用后发现效果不错,github网址:W11scan网址(https://github.com/w-digital-scanner/w11scan)


(1)工具介绍

w11scan是一款分布式的WEB指纹识别系统(包括CMS识别、js框架、组件容器、代码语言、WAF等等),管理员可以在WEB端新增/修改指纹,建立批量的扫描任务,并且支持多种搜索语法。


(2)安装步骤

由于W11scan是作者从一个纯净的ubuntu上安装的,因此我们最好选用ubuntu系统,这里我们测试的是ubuntu18.0。

<1>安装python3、pip,下载软件并安装依赖
sudo apt install -y python3 python3-pip python-celery-common gitgit clone https://github.com/boy-hack/w11scancd w11scanpip3 install -r requirements.txt

我们在安装requirements.txt中模块时,可能会提示一些模块的版本过低,我们可以采用pip安装,或单独安装这些模块。

<2>安装redis、mongodb、导出指纹数据
sudo apt install -y redis-server mongodbsudo mkdir -p /data/db # 建立Mongodb存储目录

我们需要让mongodb在65521端口上运行,先停止mongodb。
service mongodb stop

再启动。
sudo mongod --bind_ip 127.0.0.1 --port 65521

我们启动时可能会报错误。
 
解决办法:
一、两种解决方法   (1)杀掉apt-get进程:    ps aux | grep apt-get    sudo kill PID     (2)强制解锁:    sudo rm /var/cache/apt/archives/lock    sudo rm /var/lib/dpkg/lock经检测第二种方法会有用


 
我们可以发现此时我们的数据库已经监听在65521端口上了。
 
接着导入指纹:
mongorestore -h 127.0.0.1 --port 65521 -d w11scan backup/w11scan

接着输入mongo --port 65521进入mongodb shell
show dbs 查看是否有w11scan数据库创建,有则创建成功。
接着对结果进行全文索引。依然在mongodb shell状态下。
use w11scan_configdb.result.createIndex({"$**":"text"})

完成后exit退出。

<3>软件config配置

修改config.py,按照提示配置redis、mongodb用户名密码(如果按上面操作进行的,默认即可)。
 
生成django的session:
python3 manage.py migrate

<4>运行WEB端
python3 manage.py runserver //默认账号密码: admin w11scan
 

<5>运行节点
celery -A whatcms worker -l info

然后我们可以新建任务,开始检测。
 
我们可以发现我们的节点指纹就在不断的检测:
 
 
 
我们只需要等待时间,就可以将我们需要的信息扫描显示出来。


(3)使用


我们安装完成之后再次使用:
service mongodb stop //先停止mongodbsudo mongod --bind_ip 127.0.0.1 --port 65521 //再启动python3 manage.py migratepython3 manage.py runservercelery -A whatcms worker -l info




实验总结


本文主要从Web探测技术方面学习,初步完成了对服务器版本的一些信息进行获取,然后总结调研了当下的一些网站获取的方式,并在这里为大家复现了一个github上大佬的开源框架,文中可能存在一些不足,希望各位大佬指教,后续研究完成,实例代码会上传个人github:github网址(https://github.com/guoxuaa)




参考文献


HTTP学习:
菜鸟教程廖雪峰学习网站

Curl学习:
https://www.ruanyifeng.com/blog/2019/09/curl-reference.htmlhttps://www.ruanyifeng.com/blog/2011/09/curl.htmlhttps://cizixs.com/2014/05/14/curl-automate-http/

W11scan学习:
https://github.com/w-digital-scanner/w11scan



 


看雪ID:随风而行aa

https://bbs.pediy.com/user-home-905443.htm

*本文由看雪论坛 随风而行aa 原创,转载请注明来自看雪社区




# 往期推荐

1.重温搭建pwn环境

2.Windows平台下堆溢出攻击

3.Linux内核入门——驱动模块

4.CVE-2012-1876漏洞分析与利用

5.PWN学习总结

6.Java反编译_class爆破与javaagent






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存