学会主机及端口等一些基本的网络扫描程序设计技术。
目标主机扫描是网络功防的基础和前提,扫描探测一台目标主机包括:确定该目标主机是否活动、目标主机的操作系统、正在使用哪些端口、对外提供了哪些服务、相关服务的软件版本等等,对这些内容的探测就是为了“对症下药”,为攻防提供参考信息。
对主机的探测工具非常多,比如大名鼎鼎的nmap、netcat、superscan,以及国内的x-scanner等等。
今天我们自己动手做扫描软件或工具。
知识点:进一步理解 new Socket()、Process类和ICMP
1. 程序设计第一步:主机扫描(远程主机探测技术)
去发现一台在线或活跃的主机,及使用的操作系统(通过开放的端口,Win系列开放135端口,UNIX系列开放111端口);
新建Java包,命名scanner,创建主机扫描程序HostScanner.java,窗口界面如图9.1所示,并在“主机扫描”按钮中设置主机探测关键代码,如:
InetAddress addr=InetAddress.getByName(host);//host为IP地址
status=addr.isReachable(timeOut);// timeOut等待时间
若status的值为真,则表示该主机是活跃的,否则可能不存在或离线。
private int getLastNum(String ip)
{
String[] group;
ip = ip.replace('.', '/');
group = ip.split("/");
int num = Integer.parseInt(group[3]);
return num;
}
//实现IP地址加1
private String StringIPAddOne(String ip)
{
String[] group;
ip = ip.replace('.', '/');
group = ip.split("/");
int num = Integer.parseInt(group[3]) + 1;
return group[0]+"." + group[1] + "." + group[2] + "." + num;
}
获取最后一个字节和ip地址加一的函数如上
在扫描按钮下键入以下代码:
String ipAddress1 = jTextField1.getText();
String ipAddress2 = jTextField2.getText();
Thread scan = new Thread()//用一个线程专门来接收信息
{
public void run()
{
String host = ipAddress1;
int ipNum = getLastNum(ipAddress1);
int endIpNum = getLastNum(ipAddress2);
try
{
int timeOut = 100;//毫秒
while(ipNum <= endIpNum)
{
InetAddress addr = InetAddress.getByName(host);
boolean status = addr.isReachable(timeOut);
if(status == true)
{
jTextArea1.append(host + "reachable \r\n");
}else
{
jTextArea1.append(host + "is not reachable \r\n");
}
host = StringIPAddOne(host);
ipNum ++;
}
}catch(Exception e)
{
e.printStackTrace();
}
}
};
scan.start();//启动该线程
实现命令行执行:
try
{
String cmd = jTextField3.getText();
Process pro = Runtime.getRuntime().exec(cmd); //cmd为字符串命令, 会引起异常,需要try
InputStream in = pro.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in,"GB2312"));
String msg;
while((msg=br.readLine())!= null)
{
jTextArea1.append(msg + "\n");
}
}catch(Exception e)
{
e.printStackTrace();
}
2. 程序设计第二步:端口扫描技术
扫描目的主机开放的端口:攻(寻找目的主机开放的端口)与防(检测本机异常开放的端口)。基本的端口扫描技术包括:
i. New Socket(host, port);
ii. TCP Connect端口扫描;
创建端口扫描程序PortScannerJFrame.java,主界面如图所示。
扫描:
host = jTextField2.getText();
startPort = jTextField3.getText();
endPort = jTextField4.getText();
try
{
Thread scan = new Thread()//用一个线程专门来接收信息
{
public void run()
{
String msg = null;
int port = Integer.parseInt(startPort);
while(port <= Integer.parseInt(endPort))
{
try
{
Socket socket = null;
socket = new Socket(host,port);
//socket.connect(new InetSocketAddress(host,port), 150);
msg = "端口:" + port +" is open! \r\n";
jTextArea1.append(msg);
jTextArea1.paintImmediately(jTextArea1.getBounds());
}catch(Exception e)
{
msg = "端口:" + port +" is closed! \r\n";
jTextArea1.append(msg);
jTextArea1.paintImmediately(jTextArea1.getBounds());
System.out.println(msg);
}
port ++;
}
}
};
scan.start();//启动该线程
}catch(Exception e)
{
e.printStackTrace();
}
快速扫描:
多线程扫描:
先实现内部类:
class HandlerScanner implements Runnable
{
String host;
int start,end,threadNo;
public HandlerScanner(String host, int start, int end, int threadNo)
{
this.host = host;
this.start = start;
this.end = end;
this.threadNo = threadNo;
}
public void run()
{
for(int port=start; port<end+1;port++)
{
try
{
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host,port),200);
jTextArea1.append(port + " is open!\r\n");
jTextArea1.paintImmediately(jTextArea1.getBounds());
socket.close();
}catch(Exception e)
{
jTextArea1.append(port + " is closed!\r\n");
jTextArea1.paintImmediately(jTextArea1.getBounds());//实现端口关闭的显示
e.printStackTrace();
}
}
jTextArea1.append("报告: " + threadNo + " 号 线程扫描结束。\r\n");
}
}
在多线程扫描键入:
host = jTextField2.getText();
startPort = jTextField3.getText();
endPort = jTextField4.getText();
int startPortNum = Integer.parseInt(startPort);
int endPortNum = Integer.parseInt(endPort);
HandlerScanner hs1 = new HandlerScanner(host,startPortNum,startPortNum+(endPortNum-startPortNum)/2,1);
Thread t1 = new Thread(hs1);
t1.start();
HandlerScanner hs2 = new HandlerScanner(host,startPortNum+(endPortNum-startPortNum)/2 +1,endPortNum,2);
Thread t2 = new Thread(hs2);
t2.start();