1.1、工具简介
端口扫描工具的主要功能就是用户输入一个IP地址,后端对其进行扫描,判断其端口的开放情况,如果开放,可能是什么服务。端口扫描这一工作主要是在渗透测试的信息收集阶段使用,通过扫描目标主机的端口开放情况,来进一步判断是否具有可利用的攻击点。信息收集在整个渗透测试过程中极其重要,直接关系到能否顺利渗透目标主机,信息收集的越全面,攻击者可利用的攻击点越多,越可能实现对目标主机的渗透。
功能介绍:
- 对指定ip进行指定端口进行扫描,获取目的ip的端口开放情况
- 扫描模式:TCP全连接扫描、TCP半连接扫描(待实现)
- 通过发送空信息,获取开放端口对应服务的应答,获取指纹信息,从而判断服务类别
- 端口开放情况会通过日志打印出来
输入:
- ip地址或ip地址组,用逗号隔开
- 待扫描的端口组:0-65535,左开右闭
输出:
- 通过日志打印端口开放情况,并且返回数据到前端
1.2、后端实现代码
ScanApp.java:
扫描器启动类,接收前端请求的数据,启动Scanner类
package com.sducsrp.csrp.controller.ToolsController.ScanPort;
import com.sducsrp.csrp.common.Constants;
import com.sducsrp.csrp.common.Result;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
* 扫描器启动类
*/
@RestController
@RequestMapping("/tools/")
public class ScanApp {
// {ip='127.0.0.1', port=445, service='null', isOpen=true, banner='null'}
public static String result;
public int count = 0;
@RequestMapping("/scan_port")
public @ResponseBody Result scan(@RequestParam(value = "ips") String ips,
@RequestParam(value = "ports") String ports,
HttpServletResponse response){
result="";
// 待扫描的ip地址或ip地址组
System.out.println(ips+" "+ports);
Scanner.start(ips,ports);
System.out.println("from ScanApp:"+result);
Result res=new Result(Constants.CODE_200,null,result);
return res;
}
}
Scanner.java:
端口、指纹扫描器类
主要功能:
- 解析输入的ip地址、端口
- 新键扫描任务ScanJob扫描引擎进行端口扫描
- 两种扫描方式:TCP全连接扫描、TCP半连接扫描(未完成)
方法:
-
public static void start(String ips, String ports)
开始方法:解析端口、IP地址
@param ips 输入的待扫描ip列表
@param ports 输入的待扫描端口
-
public static void scanAllPort(String ip, int portStart, int portEnd)
扫描某ip的对应端口
@param ip ip地址
@param portStart 开始扫描的的端口
@param portEnd 停止扫描的端口
-
public static void scan(String ip, int port)
对ip:port进行扫描
@param ip ip地址
@param port 端口
package com.sducsrp.csrp.controller.ToolsController.ScanPort;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class Scanner {
// 日志
private static Logger logger = Logger.getLogger("Scanner");
// 使用多线程扫描
private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(30,40,1000,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
/**
* 开始方法
* @param ips 输入的待扫描ip列表
* @param ports 输入的待扫描端口
*/
public static void start(String ips, String ports) {
// 解析端口
String[] portArray = ports.split("-");
int portStart = Integer.parseInt(portArray[0]);
int portEnd = Integer.parseInt(portArray[1]);
logger.info("[-] Ports: " + ports);
System.out.println("[-] Ports: " + ports);
// 解析ip地址,并扫描
if (ips.indexOf(',') != -1) {
String[] ipList = ips.split(",");
logger.info("[-] IP list: " + ipList.toString());
System.out.println("[-] IP list: " + ipList.toString());
for (String ip : ipList) {
scanAllPort(ip,portStart,portEnd);
}
}else if (ips.indexOf('/') != -1){
// TODO 支持ip地址网段的解析
String[] ipArray = ips.split("/");
String ipAddress = ipArray[0];
int mask = Integer.parseInt(ipArray[1]);
String[] ipSplit = ipAddress.split(".");
}else {
scanAllPort(ips,portStart,portEnd);
}
// 扫描任务都完成后,程序停止
try{
while(true){
if(poolExecutor.getActiveCount() == 0){
logger.info("[-] Scan job all finish");
System.out.println("[-] Scan job all finish");
//System.exit(-1);
break;
}
Thread.sleep(1000);
}
}catch (Exception ex){
logger.warning("End with exeception, ex: " + ex.getMessage());
System.out.println("End with exeception, ex: " + ex.getMessage());
}
//System.exit(-1);
}
/**
* 扫描某ip的对应端口
* @param ip ip地址
* @param portStart 开始扫描的的端口
* @param portEnd 停止扫描的端口
*/
public static void scanAllPort(String ip, int portStart, int portEnd){
for (int port = portStart; port <= portEnd; port++){
scan(ip,port);
}
}
/**
* 对ip:port进行扫描
* @param ip ip地址
* @param port 端口
*/
public static void scan(String ip, int port){
// 执行扫描任务
poolExecutor.execute(new ScanJob(new ScanObject(ip,port), ScanEngine.TCP_FULL_CONNECT_SCAN));
}
}
ScanJob.java:
扫描任务类,执行具体的扫描任务
package com.sducsrp.csrp.controller.ToolsController.ScanPort;
/**
* 扫描任务类,执行具体的扫描任务
*/
public class ScanJob implements Runnable{
// 扫描信息
private ScanObject object;
// 扫描类型
private String scanType;
public ScanJob(ScanObject object, String scanType) {
this.object = object;
this.scanType = scanType;
}
@Override
public void run() {
ScanEngine.scan(object, scanType);
}
}
ScanEngine.java:
扫描器引擎
实现具体的扫描逻辑,提供扫描能力(TCP全连接和半连接扫描)
package com.sducsrp.csrp.controller.ToolsController.ScanPort;
import java.net.ConnectException;
import java.net.Socket;
import java.util.logging.Logger;
/**
* 扫描器引擎
* 实现具体的扫描逻辑,提供扫描能力(TCP全连接和半连接扫描)
*/
public class ScanEngine {
private static Logger logger = Logger.getLogger("TCPFullConnectScan");
public static final String TCP_FULL_CONNECT_SCAN = "TCP_FULL_CONNECT_SCAN";
public static final String TCP_HALF_CONNECT_SCAN = "TCP_HALF_CONNECT_SCAN";
public static ScanObject scan(ScanObject object, String scanEngine){
switch (scanEngine){
case TCP_FULL_CONNECT_SCAN:
return tcpFullConnectScan(object);
case TCP_HALF_CONNECT_SCAN:
return tcpHalfConnectScan(object);
}
return tcpFullConnectScan(object);
}
/**
* tcp全连接扫描
* @param object
* @return
*/
private static ScanObject tcpFullConnectScan(ScanObject object){
try{
// 全连接扫描,发现可用服务
Socket socket = new Socket(object.getIp(),object.getPort());
object.setOpen(true);
object.setService();
logger.info("[-] Find service :"+ object);
System.out.println("[-] Find service :"+ object);
ScanApp.result=ScanApp.result+object;
socket.close();
} catch (ConnectException e) {
} catch (Exception e){
// 出现其他异常
logger.info("[-] " + object.toString() + "end with unexecepted exeception:" + e.getMessage());
System.out.println("[-] " + object.toString() + "end with unexecepted exeception:" + e.getMessage());
ScanApp.result=ScanApp.result+object;
}
return object;
}
/**
* TPC 半连接扫描
* @param object
* @return
*/
private static ScanObject tcpHalfConnectScan(ScanObject object){
// TODO 待实现tcp半连接扫描
return object;
}
}
ScanObject:
扫描信息实体
package com.sducsrp.csrp.controller.ToolsController.ScanPort;
import java.util.HashMap;
import java.util.Map;
/**
* 扫描信息实体
*/
public class ScanObject {
private String ip;
private int port;
private String service;
private Boolean isOpen;
private String banner;
// 存放服务指纹和服务的对应关系 banner -> service
private static Map<String,String> bannerMaps = new HashMap<>();
// 存放常见端口与服务的对应关系 port -> service
private static Map<Integer,String> portMaps = new HashMap<>();
static {
bannerMaps.put("ssh","SSH");
portMaps.put(22,"SSH");
bannerMaps.put("ftp","FTP");
portMaps.put(21,"FTP");
portMaps.put(20,"FTP");
bannerMaps.put("smtp","SMTP");
portMaps.put(25,"SMTP");
bannerMaps.put("mysql","MySQL");
portMaps.put(3306,"MySQL");
bannerMaps.put("RemoteDesktop","RemoteDesktop");
portMaps.put(3389,"RemoteDesktop");
}
public ScanObject(String ip, int port) {
this.ip = ip;
this.port = port;
}
public Boolean getOpen() {
return isOpen;
}
public void setOpen(Boolean open) {
isOpen = open;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getService() {
return service;
}
public void setService() {
// 先根据port判断服务类型
if (portMaps.containsKey(this.port)){
this.service = portMaps.get(this.port);
}
if (banner != null && !banner.equals("")){
for (String key : bannerMaps.keySet()) {
if (banner.toLowerCase().contains(key)) {
this.service = bannerMaps.get(key);
break;
}
}
}
}
public String getBanner() {
return banner;
}
public void setBanner(String banner) {
this.banner = banner;
}
@Override
public String toString() {
return ip +","+ port +"," + service +"," + isOpen +"," + banner+";";
}
}
1.3、前端实现代码
<!--端口扫描工具-->
<!--把后端识别端口指纹的功能关闭掉了,不然太慢
1.设置响应时间更长
2.关闭指纹识别-->
<template>
<div class="bf_form">
<div class="bf_form_main">
<h3 class="header blue lighter bigger">
Please Enter Ips(Ip1,Ip2) And Ports(Port1-Ports2)
</h3>
<el-input v-model="ips" style="width: 250px;margin-right: 50px" placeholder="ips"></el-input>
<el-input v-model="ports" style="width: 250px;margin-right: 50px" placeholder="ports"></el-input>
<el-button @click="scan_start">scan</el-button>
</div><!-- /.widget-main -->
</div><!-- /.widget-body -->
<el-card style="width: 40%;height: 500px;margin-left: 30%;margin-top: 5%">
<p>返回结果:</p>
<p>{{ myresult }}</p>
</el-card>
</template>
<script>
// import router from '../../../router/index'
import request from "@/utils/request";
export default {
data() {
return {
ips:'',
ports:'',
myresult:''
}
},
methods:{
scan_start(){
request.get("/tools/scan_port",{
params:{
ips:this.ips,
ports:this.ports
}
}).then(res =>{
alert("1");
this.myresult=res.data
})
}
}
}
</script>
<style>
.wrapper {
height: 100vh;
background-image: linear-gradient(to bottom right, #000000, #483D8B);
overflow: hidden;
}
</style>