敢不敢尝试自己写个安全扫描器(java)
年少轻狂的博主毕设题目选择了“网络扫描器的设计与实现”,不料看似简单的题目,却隐藏着一个个巨大的难题。对于菜鸟博主而言,这无疑是一次顶着延毕风险的挑战!然而庆幸的是虽然存在好多功能缺陷、代码bug数不清,最终还是浑水摸鱼通过了毕业考核。无论如何,该毕设项目还是倾注了菜鸟博主很多心血的,所以还是斗胆在这里分享一下吧,也欢迎各位大佬在评论区指正批评哦~
网络扫描器的设计与实现
题目要求
利用网络扫描技术,开发一款基于B/S架构的网络扫描器,要求系统可以通过向远程或本地主机发送探测数据包、获取主机的响应,并根据反馈的数据包,进行解包、分析,从而发现网络或主机的配置信息、端口分配、提供的网络服务、服务器的具体信息等。网络扫描器分为扫描客户端和扫描服务端,扫描服务端也称为扫描引擎,扫描客户端为系统管理员提供操作界面。应包含以下功能模块:
(1)扫描引擎管理:负责扫描引擎、IP地址区间、端口范围等配置管理。
(2)扫描任务管理:负责扫描任务的调度,用户可添加、删除、修改扫描任务,对于执行中的任务可查看其运行状态。主要有以下三种扫描任务:1)主机扫描,输入起始 IP 与结束 IP,在这个 IP 段的范围内进行测试,结果显示处于存活状态的主机IP等信息。2)端口扫描,提供输入界面,输入起始 IP与结束 IP,在这个 IP 段的范围内进行测试,设置扫描端口范围,结果显示主机开放的端口信息。3)漏洞扫描,针对目标主机的特定服务检查是否有安全漏洞。
(3)扫描通讯管理:负责处理各个模块和扫描引擎之间所有命令、响应、通知等消息,将各种消息包装成相应的报文格式,交由扫描引擎完成相应的功能,并将扫描结果回送处理。
(4)策略插件管理:负责给用户定制各种扫描策略,以及这些策略需要使用哪些扫描插件。
(5)资产管理:资产即用户需要管理的设备,含主机、服务器、网络设备等,资产即扫描任务的目标设备。
一、环境配置
硬件环境
PC客户端台式机或笔记本
4.00GB内存及以上
Inter® Core™ i7-2617M CPU @ 1.50GHz
软件环境
windows7及以上版本Eclipse Jee
JDK1.8
mySQL 8
Chrome/ FireFox/ Internet Explorer 7.0+
二、系统技术架构
该项目是一款基于B/S架构的网络扫描器软件系统。系统前端使用了HTML、CSS、JavaScript等语言进行编写,部分页面使用了Bootstrap框架,以及Ajax技术。后端使用的是原生JSP+Servlet+JavaBean开发的经典MVC模式。
本系统的数据库设计,是按照规范步骤进行的。其中,在进行数据库逻辑结构设计时,得出了系统E-R图,消除了属性冲突、命名冲突和结构冲突,并进行了多次优化,为了兼顾程序开发做连接查询时较为方便,选择引入逻辑外键,最终保证该数据库达到3NF范式。
连接数据库时没有使用myBatis,而使用了轻型框架DBUtils+数据库连接池。
三、系统主要功能
根据项目参与者的用户特点,考虑到用户对网络扫描器的需求,对该网络扫描器系统进行了功能性设计。
该系统主要包含以下功能:
1.用户账户信息管理
普通用户可以进行个人账号的注册、登录,以及个人信息的修改。管理员用户具有普通用户的所有权限,此外还拥有以下特权:可以查看并管理所有用户的基本信息(密码除外);可以查看并管理所有用户发起的任务;可以查看并管理所有用户添加的资产、插件。
2.扫描引擎管理
负责主机扫描的IP地址区间、端口范围的配置管理。在设置好这些参数之后才可以进行扫描任务的执行操作。因此该功能并非一个独立的功能,而是添加新的扫描任务时的一个必需的步骤。
3.扫描任务管理
负责扫描任务的调度。用户可发起新的扫描任务,也可以参观扫描任务列表,查看各项扫描任务的状态,并对已添加的扫描任务进行启动、删除或停止等操作。主要有以下四种扫描任务:
①主机扫描:输入起始 IP 与结束 IP,在这个 IP 段的范围内进行测试,结果显示处于存活状态的主机IP、主机名称、主机MAC等信息。
②端口扫描:提供输入界面,让用户给定一个目标主机IP,设置扫描端口范围,结果显示主机开放的端口信息。
③漏洞扫描:针对目标主机的特定服务检查是否有安全漏洞,可以选择弱口令扫描、使用第三方插件进行扫描等方式。
④操作系统类型识别:提供一个目标主机(可以从用户添加的资产中选择),对其进行操作系统和用户所用浏览器类型的识别。
除了可以对扫描任务进行添加、删除、分类查询等操作,为了方便用户使用方便,我们还需对任务扫描后得到的结果进行人性化处理,比如允许用户保存该扫描结果,并可以对其进行详情查看、删除等管理操作。
4.扫描通讯管理
用户可以选用命令行形式,在系统中仿命令行页面中完成查看任务详情、查看扫描结果等相关操作。
5.策略插件管理
负责让用户选定使用怎样的扫描策略,包括执行扫描任务时分配多少个线程进行扫描,用户也可以上传和管理自己想要使用的插件。
6.资产管理
资产即扫描任务的目标设备,针对于用户主机扫描任务得到的结果,用户可以选择添加到资产,这样就可以在资产列表中找到,方便用户对此资产进行进一步扫描操作。这样使得扫描任务有了更好的针对性。
四、技术攻关
主机扫描
主机扫描原理
主机扫描,即扫描一个网段中的活跃主机。其原理就是本机尝试向目标主机发送ICMP协议包,根据本机接收到的ICMP应答报文的响应时间长短,判断目标主机是否可达。若可达,则记录下该主机的IP地址,然后就可以使用ARP协议解析出对应的MAC地址,使用反向域名解析技术解析出主机名等信息。ICMP协议的一个典型应用就是我们大家熟知的ping命令,ping命令通常用来检查网络的可用性和连通性。因此我们可以直接使用ping命令尝试对一个网段内的所有主机一一进行连通性测试,若响应时间过长,则认定为目的主机不可达。
本系统主机扫描功能的实现
首先,为了提高扫描效率,本系统在主机扫描和端口扫描功能的设计时运用了线程池技术。
线程池,是一个可以容纳多个线程的容器,存放在线程池中的线程,在执行完所分配给它的任务后,不会立即被销毁,而是更改为空闲状态,并执行下一个任务。因为考虑到如果用户在扫描引擎中设置的主机扫描IP地址范围很大,为保证系统高效运行,则必须使用多线程技术。而线程的创建和销毁本身会消耗不少的时间和资源,因此使用线程池技术,可以反复利用来执行任务,减少了时间和资源的消耗。而本系统采用的是定长线程池(FixedThreadPool),这种线程池具有如下特点:①核心线程处于空闲状态时不会被回收,除非线程被关闭;②当所有线程都处于活动状态时,新的任务会在任务队列中等待,直到有线程转化为空闲状态;③任务队列的大小无限制。
其次,在本系统在进行主机扫描时,首先创建线程池。由于需要根据用户在系统线程管理功能模块的设置,为每个线程分配扫描的主机个数,即IP地址的个数,所以先将合法性检查后的字符串形式的IP地址转换成长整型,然后再计算,并为每个线程分配执行扫描任务的IP区间。最后启动线程池使其按制定好的线程扫描策略执行任务。通过使用InetAddress类中的isReachable(int timeout)方法测试连通性,设定的超时时间是100ms,若目标主机可以在这个时间段内连通,则将其IP地址添加在扫描结果集合中。本系统主机扫描功能实现的流程图如下图所示。
- 主机扫描多线程的分配和开启
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.zhscan.entity.Host;
import com.zhscan.entity.Task;
import com.zhscan.util.IpUtils;
public class HostScanService implements Runnable{
private int step;
private Task task;
private static List<Host> hosts ;
private volatile boolean exit = false;
public HostScanService(int step, Task task) {
super();
this.step = step;
this.task = task;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
public static List<Host> getHosts() {
return hosts;
}
public void setExit(boolean exit) {
this.exit = exit;
}
public void run() {
while (!exit) {
try {
hosts = begin();
} catch (InterruptedException e) {
}
}
}
public List<Host> begin() throws InterruptedException {
long beginIP = IpUtils.ipToLong(task.getBeginIP());
long endIP = IpUtils.ipToLong(task.getEndIP());
setStep(step);
List<Long> list = new LinkedList<>();
for (long i = beginIP; i <endIP ; i+=step) {
list.add(i);
}
ExecutorService service = Executors.newFixedThreadPool(list.size());
long startTime = System.currentTimeMillis();
int length = list.size() - 1;
for (int i = 0; i <= length&&(!exit); i++) {
ScanHandler scanHandler = new ScanHandler();
long start = list.get(i);
long end = start + step;
if (i == length) {
scanHandler.setParams(start,Math.min(end, endIP),endIP);
} else {
scanHandler.setParams(start,end,endIP);
}
service.execute(scanHandler);
}
service.shutdown();
List<Host> success =null;
while(!exit){
if(service.isTerminated()){
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end - startTime) + "ms");
System.out.println("---------------------------------------");
success = new OpenList().getSuccess();
// System.out.println(success);
for(int i=0;i< success.size();i++){
success.get(i).setResponseTime(end-startTime);
// System.out.println(success.get(i).toString());
}
break;
}
}
exit=true;
return success;
}
}
- 保存扫描结果的类
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.zhscan.entity.Host;
public class OpenList{
private static List<Host> success=new ArrayList<>();
public List<Host> getSuccess() {
return success;
}
void addList(String i){
Host host=new Host(i,getHostNameByAdress(i),getMacByIp(i),0);
success.add(host);
}
public String getHostNameByAdress(String ip){
String[] ii=ip.split("\\.");
byte[] ips=new byte[4];
for(int i=0;i<4;i++){
ips[i]=(byte)(Integer.parseInt(ii[i]));
}
try {
InetAddress inetAddress = InetAddress.getByAddress(ips);
if (inetAddress .getHostName().equals(ip)) {
return " ";
}
return InetAddress.getByAddress(ips).getHostName();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return " ";
}
public static String command(String cmd) throws Exception{
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
InputStream in = process.getInputStream();
StringBuilder result = new StringBuilder();
byte[] data = new byte[256];
while(in.read(data) != -1){
String encoding = System.getProperty("sun.jnu.encoding");
result.append(new String(data,encoding));
}
return result.toString();
}
public String getMacByIp(String ip){
String result = null;
try {
result = command("arp -a "+ip);
//使用arp解析MAC地址
} catch (Exception e) {
e.printStackTrace();
}
String regExp = "([0-9A-Fa-f]{2})([-:][0-9A-Fa-f]{2}){5}";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(result);
StringBuilder mac = new StringBuilder();
while (matcher.find()) {
String temp = matcher.group();
mac.append(temp);
}
return mac.toString();
}
}
- 具体进行的扫描操作
import java.io.IOException;
import java.net.InetAddress;
import com.zhscan.util.IpUtils;
public class ScanHandler implements Runnable{
private OpenList openIP=new OpenList();
private long start;
private long end;
private long end_IP;
public void setParams(long start, long end,long end_IP){
this.start=start;
this.end=end;
this.end_IP=end_IP;
}
public void scan(long item){
String currentIp=IpUtils.longToIp(item);
System.out.println("testing ip: "+currentIp);
//输出测试,便于观察到正在扫描的主机IP
try{
InetAddress address = InetAddress.getByName(currentIp);
if(address.isReachable(100))
openIP.addList(currentIp);
}catch (IOException e) {
}
}
@Override
public void run() {
for(long item = start; item < end; item++){
if (Thread.currentThread().isInterrupted()) {
System.out.println("interrupted!");
break;
}
scan(item);
}
if(end== end_IP){
scan(end);
}
}
}
计算IP地址的工具类
public class IpUtils {
public static long ipToLong(String strIp) {
String[] s = strIp.split("\\.");
long ip = (Long.parseLong(s[0]) << 24)
+ (Long.parseLong(s[1]) << 16) +
(Long.parseLong(s[2]) << 8)
+ (Long.parseLong(s[3]));
return ip;
}
public static String longToIp(long longIp) {
//采用SB方便追加分隔符 "."
StringBuffer sb = new StringBuffer("");
sb.append(String.valueOf(longIp>>24)).append(".").
append(String.valueOf((longIp&0x00ffffff)>>16)).append(".").
append(String.valueOf((longIp&0x0000ffff)>>8)).append(".").
append(String.valueOf(longIp&0x000000ff));
return sb.toString();
}
}
端口扫描
端口扫描原理
端口扫描的方式有很多,但端口扫描的原理大致都是相同的,就是通过socket与目的主机的端口尝试建立连接,若可以成功连接接说明该端口是开放的,否则该端口不可用。
本系统端口扫描功能的实现
本系统采用的端口扫描原理比较简单,利用Java中提供的Socket类,遍历用户感兴趣的目标主机的端口,并通过调用connect()方法对其进行连接尝试,在本系统中,尝试连接的时长暂定于100ms。如果连接成功,则说明目标主机的该端口是开放的、处于监听状态;否则说明该目的主机的这个端口是关闭的或者处于禁用状态。同样,本系统在进行端口扫描时仍然采用了线程池技术,按照用户指定的线程策略,为每个线程分配扫描的端口数。这个技术的一个最大的优点是,不需要任何权限,系统中的任何用户都有权利使用这个调用。但是这种扫描方式也有缺点,会在目的主机的日志记录中留下扫描痕迹,容易被防火墙和IDS检测到。而connect()方法进行端口扫描的具体原理示意图见下图。
端口扫描核心代码
public void scan(int item){
System.out.println("testing Prot"+item);
Socket socket=null;
try{
socket=new Socket();
SocketAddress address=new InetSocketAddress(IP, item);
socket.connect(address,100);
socket.close();
OpenPort.addList(item);
}catch (IOException e) {
}
}
漏洞扫描
弱口令扫描
在网络环境中,过于简单的口令面临着非常大的安全风险。众所周知,口令的长度越长、口令内容越复杂,系统账户的安全性就越高,但总会有某些用户图省事而设置的口令过于简短。因此,对于具有责任感的管理员而言,及时检测出口令存在的弱项是极为关键的一环,因为只有在此基础上才可以采取进一步的安全措施。现在有很多弱口令扫描工具允许使用密码字典来进行暴力破解,如John the Ripper等,根据破解的难度来判断该口令的强度或安全性。但它们大多是仅用于Linux/UNIX操作系统环境下。在适用于Windows系统的本项目中,使用了口令检测工具类以及口令检测参数文件。其原理就是先将获取到的用户口令密文进行解密,然后从长度、字母数字组合、逻辑字母顺序、键盘上相邻字母顺序等几方面对用户口令的强度进行检查,具体检测指标如下图所示。然后找出该口令安全性哪些方面不符合安全指标,将这些方面以文字形式存放到结果集中传送至前端展现给用户。
Struts2漏洞扫描
Apache Struts是一套开源MVC框架,常应用于开发企业级Java Web项目。其提供的Struts 2.3.5 至 2.3.31版本及2.5至2.5.10版本存在远程代码执行漏洞(CNNVD -201703-152 ,CVE -2017-5638)。该漏洞是由于文件上传功能出现异常,用户输入的错误信息没有得到系统正确的处理,远程攻击者可以利用此漏洞,发送恶意数据包,通过构造HTTP请求头中的Content-Type字段值可能造成远程代码执行。
本系统通过POC 进行漏洞概念验证,其原理是通过使用引入httpclient、okhttp等jar包,利用编译好的POC_201909161647.class文件中的check()方法,分析被检测的目标主机返回的“User-Agent”信息,从而判断漏洞是否存在。
反序列化漏洞扫描
序列化和反序列化的概念我们并不陌生。对象在序列化过程中会将其当前状态写入到临时或持久性存储区。而反序列化时我们从存储区中读取该数据,并将其还原为对象。由于很多站点及一些API接口存在Java的反序列化功能,于是攻击者可以通过构造特定的恶意对象序列化后的流,使得目标反序列化,利用反射机制避免Java的约束机制,在程序运行期间直接访问目标对象或对其属性进行操作,从而达到自己的恶意预期行为,这其中当然也避免不了系统命令的执行[12]。Weblogic XMLDecoder反序列化漏洞(CVE_2017_10271),是一种远程代码执行漏洞,也是反序列化漏洞的一种,黑客可以构造请求对运行WebLogic中间件的主机进行攻击。就比如我们完全可以通过Java反射机制来调用本地的计算器程序,当然也可以调用本地的其他程序,比如一段以攻击为目的的恶意代码,因此这种漏洞一旦被利用,危害性还是很大的。本系统则是先根据该漏洞特点,通过利用相关jar包以及POC_201911.class文件中的check()方法,分析和检测了该漏洞。
使用第三方插件扫描
- 上传文件的Servlet
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.zhscan.entity.Plagin;
import com.zhscan.entity.User;
import com.zhscan.service.PlaginService;
/**
* Servlet implementation class UploadServlet
*/
@MultipartConfig //使用MultipartConfig注解标注改servlet能够接受文件上传的请求
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = "D:/eclipse/workspace/graduationDesign/networkScanner/WebContent/WEB-INF/upload";
String fileConf="";
String filename="";
File file = new File(savePath);
User u =(User) request.getSession().getAttribute("user");
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+"目录不存在,需要创建");
//创建目录
file.mkdir();
}
//消息提示
String message = "";
try{
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if(!ServletFileUpload.isMultipartContent(request)){
//按照传统方式获取数据
fileConf=request.getParameter("fileconf");
//return;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for(FileItem item : list){
//如果fileitem中封装的是普通输入项的数据
if(item.isFormField()){
//String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
//System.out.println(name + "=" + value);
}else{//如果fileitem中封装的是上传文件
//得到上传的文件名称,
filename = item.getName();
System.out.println(filename);
if(filename==null || filename.trim().equals("")){
continue;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(filename.lastIndexOf("/")+1);
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "/" + filename);
//创建一个缓冲区
byte buffer[] = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int len = 0;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while((len=in.read(buffer))>0){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0, len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!";
}
}
}catch (Exception e) {
message= "文件上传失败!";
e.printStackTrace();
}
System.out.println(message);
System.out.println(fileConf);
String filePath=savePath + "/" + filename;
Plagin plag = new Plagin(filename, filePath, fileConf, u.getUserID());
PlaginService ps = new PlaginService();
ps.addPlagin(plag);
request.setAttribute("success", 1);
request.getRequestDispatcher("plaginmanager.jsp") .forward(request,response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 相关的JSP页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/public.css" />
<link rel="stylesheet" type="text/css" href="css/scanstrategy.css" />
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
crossorigin="anonymous">
<link href="bootstrp-fileinput/css/fileinput.css" media="all"
rel="stylesheet" type="text/css" />
<link rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.5.0/css/all.css"
crossorigin="anonymous">
<link href="bootstrp-fileinput/themes/explorer-fas/theme.css"
media="all" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
crossorigin="anonymous"></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js"
crossorigin="anonymous"></script>
<script src="bootstrp-fileinput/js/plugins/piexif.js"
type="text/javascript"></script>
<script src="bootstrp-fileinput/js/plugins/sortable.js"
type="text/javascript"></script>
<script src="bootstrp-fileinput/js/fileinput.js" type="text/javascript"></script>
<script src="bootstrp-fileinput/js/locales/fr.js" type="text/javascript"></script>
<script src="bootstrp-fileinput/js/locales/es.js" type="text/javascript"></script>
<script src="bootstrp-fileinput/themes/fas/theme.js"
type="text/javascript"></script>
<script src="bootstrp-fileinput/themes/explorer-fas/theme.js"
type="text/javascript"></script>
</head>
<body>
<%@ include file="header.jsp"%>
<c:if test="${isLogin !=1 }">
<%
response.sendRedirect("login.jsp");
%>
</c:if>
<script type="text/javascript" >
var issaved = '<%=request.getAttribute("success")%>';
if(issaved==1){
alert("插件上传成功!");
request.removeAttribute("success");
}
</script>
<div class="Bott">
<div class="wrapper clearfix">
<div class="you fl">
<div class="address mt" id="add">
<div class="wrapper clearfix">
<a href="index.jsp" class="fl">首页</a><span> / </span><a
href="scanstartegy.jsp">扫描策略</a> <span> / </span><a
href="plaginmanager.jsp" class="on">插件管理</a> <a class="goback"
href="index.jsp">返回首页></a>
</div>
</div>
<form action="UploadServlet" method="post"
enctype="multipart/form-data">
<label>注册表项:</label>
<input id="fileconf" class="fileconf" type="text" class="file" data-theme="fas"
name="fileconf">
<hr>
<div class="file-loading">
<input id="file" type="file" class="file" data-theme="fas"
name="myfile" accept=".jar,.bat,.zip" onChange="getFilePath()">
</div>
<br>
<div class="de">
<input type="submit" value="确定上传" /><input type="button" onclick="location.href = 'listPlagins?way=1'"
value="我的插件" /><input type="button" onclick="history.go(-1);" value="返回" />
</div>
</form>
</div>
</div>
</div>
<!--返回顶部-->
<%@ include file="gotop.jsp"%>
<%@ include file="footer.jsp"%>
<script type="text/javascript">
function getFilePath() {
var file = $("#file").val();
var suffix = file.substr(file.lastIndexOf("."));
if (suffix != '.jar' && suffix != '.zip' && suffix != '.bat') {
alert("请上传.jar或.zip或.bat格式的文件!");
$("#file").val('');
return;
} else {
$("#fileconf").val(file);//获取文件所在地址
}
}
</script>
</body>
</html>
前端样式css美化
@charset "UTF-8";
.thirdplag {
width: 100%;
z-index: 30;
padding: 15px 0;
text-align: center;
border-bottom: 1px solid #e6e6e6;
background: #F9FBFF;
}
.thirdplag h3 {
padding-bottom: 10px;
/* border-bottom: 1px solid #e6e6e6; */
}
.thirdplag p{
padding: 10px;
font-size:16px;
}
.thirdplag .bc {
margin-top: 30px;
margin-bottom: 30px;
display: flex;
/* justify-content: space-around; */
}
.thirdplag .bc input {
display: inline-block;
width: 165px;
height: 36px;
line-height: 20px;
text-align: center;
background: #fff;
border: 1px solid #e6e6e6;
}
.thirdplag .bc input:nth-child(1){
color: #1b41c0;
margin-left: 595px;
border: 1px solid #1b41c0;
}
.thirdplag .bc a , .thirdplag .bc a{
width: 20px;
height: 20px;
margin-left: 1250px;
}
/* .hostthread div a img , .portthread div a img{
width: 100%;
display: block;
}
*/
.shortselect{
background: #fafdfe;
height: 35px;
width: 300px;
line-height: 28px;
border: 1px solid #9bc0dd;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.address a .goback {
float:right;
color:#1b41c0;
}
.osresult {
margin-left:400px;
}
.osresult h3 {
margin-bottom:10px;
}
.pannel .vulform {
width: 100%;
height: 430px;
background: #F9FBFF;
}
.pannel form .startbtn input {
width: 280px;
background: #1B41C0;
font-size: 16px;
border: none;
color: #fff;
margin-left: 555px;
float: left;
}
.pannel .vulform .set1 .li1 {
margin: 50px 0;
}
.pannel .vulform .weakinfo{
color:#1B41C0;
margin-left:20px;
}
操作系统扫描
进行操作系统类型的识别,一种典型的方式是通过ping目标主机,利用获取到的信息中的TTL起始值,来判断操作系统类型。因为不同类型的操作系统都有默认的TTL值 。而本系统除了支持用户使用第三方插件进行扫描任务之外,也进行了对用户所使用的主机的操作系统类型和浏览器类型进行识别的功能设计。该原理就是利用request.getHeader(“User-Agent”) 来获得浏览器请求头中的User-Agent 。然后就可以在获取到的字符串中搜查到有关操作系统和浏览器类型的信息了。
总结
总结一下,我的毕设项目所做的主要工作主要有以下这些。
(1)了解了现存的网络扫描技术以及网络扫描器软件,并进一步分析了当前这些软件的优势以及存在的不足之处,针对这些不足之处,对相应的改进方法进行了探索,在此基础上进行了立项及实践。
(2)对主机扫描、端口扫描、漏洞扫描、操作系统识别等一些关键的扫描技术原理进行了深入地学习、分析,并将这些抽象的技术在该毕业设计系统中通过系统功能设计的方式进行了具体化。
(3)对多线程、线程池技术在网络扫描中的应用进行了学习和探究,并阐述了系统中线程分配功能的设计。
(4)介绍了本项目的详细开发过程,以及系统测试的过程和结果。
此外,本系统仍存在一些问题和不足,需要在接下来的开发版本中进一步完善。
(1)本系统前端设计存在不够人性化之处。在用户添加一项耗时较长的扫描任务时,应当在前端页面加上用户友好的提示性效果,比如“扫描中,请稍等”等提示语言以及可以通过进度条显示查看任务进度的功能等。这就需要在前端开发时更加深入地理解和使用前端Ajax技术。
(2)本系统的扫描任务管理功能还有尚不完善之处,在接下来的开发版本中,可以增设定时启动任务功能,这样可以使用户更加方便地、更加准时地发起扫描任务。
(3)本系统的漏洞扫描功能支持的可扫描的漏洞类型较少,且针对于网络协议的分析不够透彻、应用不够充分。
(4)需进一步加强和巩固一下本系统自身的安全性,如增设SQL注入过滤器等。
如今,互联网仍有一股强有力的发展势头,网络安全也需要日臻完善,因此该系统也需要根据实际需求不断进行修正和完善。
本系统可以在一定程度上帮助用户了解局域网内设备的运行情况、排查安全隐患,但不太适用于大型企业网络,在实际应用中仍会存在一些问题。因此,本项目目前仅可作为学习使用,若要真正投入到实际使用中,还需要进行很多方面的完善。
PS:评论区欢迎大佬指点江山,尤其是关于漏洞扫描功能实现方面,若有好的建议和计策,欢迎留言,博主将不胜感激!
最后附上毕设项目源码及毕业设计说明书等资料的地址,仅供有需要的小伙伴参考!同时希望小伙伴们赏赏光,点个点赞、关注、收藏啦啥的(手动滑稽)( ^ _ ^ )