这次是大学期间第四次项目实习,主要是利用C#技术设计一个简单的多线程端口扫描器,能够扫描网段内的各端口信息。
本次项目实习的任务是设计并实现一个简单的端口扫描器,它通过与目标主机 TCP/IP端口建立连接并请求某些服务,记录目标主机的应答,分析目标主机相关信息,从而发现目标主机某些内在的安全弱点。即实现一个端口扫描程序,判断指定的主机有哪些端口可以提供服务, 并把扫描得知的结果记录下来并显示出来。
二十一世纪是信息化、网络化的世纪,信息是社会发展的重要资源。信息安全保障能力是一个国家综合国力、经济竞争实力和生存能力的重要组成部分,是世界各国在奋力攀登的制高点。国际标准化组织(ISO)对计算机系统安全的定义是:为数据处理系统建立和采用的技术和管理的安全保护,保护计算机硬件,软件和数据不因偶然和恶意的原因遭到破坏,更改和泄露。由此可以将计算机网络的安全理解为:通过采用各种技术和管理措施,使网络系统正常运行,从而确保网络数据的可用性、完整性和保密性。所以,建立网络安全保护措施的目的是确保经过网络传输和交换的数据不会发生增加、修改、丢失和泄露等。网络安全包括技术领域和非技术领域两大部分:非技术领域包括一些制度,政策,管理,安全意识,实体安全等方面的内容;技术领域包括隐患扫描,防火墙,入侵检测,访问控制,虚拟专用网,CA认证,操作系统等方面的内容。这些技术的目标是保证信息的可控性,可用性,保密性,完整性,和不可抵赖性。其中端口扫描属于安全探测技术范畴,对应于网络攻击技术中的网络信息收集技术。
本次课设设计的是一个简单的端口扫描器,该扫描器应具备的基本功能有:
(1)支持多线程模式扫描端口;
(2)能对单个指定主机进行扫描或扫描指定网段内的主机;
(3)能扫描特定的部分端口或对指定的端口段内的端口进行逐个扫描;
(4)能够显示所开放端口的服务名称。所使用的扫描方法为TCP connect扫描,该扫描的具体实现过程为:TCP connect端口扫描服务端与客户端建立连接成功(目标端口开放)的过程如下: ① Client端发送SYN;② Server端返回SYN/ACK,表明端口开放;③ Client端返回ACK,表明连接已建立;④ Client端主动断开连接。
该扫描器工作流程为:
(1)先确定扫描范围。即扫描目的主机的IP地址和需要扫描的端口范围;
(2)确定好后给扫描器分配好线程数;
(3)开始扫描端口,结束后将扫描结果显示出来,包括开放和未开放的端口,若端口开放则还可显示该端口提供的服务。
(4)扫描结束。
private string ipStart; //起始IP地址
private string ipEnd; //结束IP地址
private int portStart; //开始端口
private int portEnd; //结束端口
private int numThread=20; //分配线程数,默认为20
private int overtime=20; //超时限制20ms
private Thread t; //定义一个线程
rivate Thread scanthread; //端口扫描线程
private bool[] done = new bool[65536];
List str; //扫描结果集
private void Form1_Load(object sender, EventArgs e)//主界面加载函数
private void checkBox1_CheckedChanged(object sender, EventArgs e)
//单主机扫描模式选择函数
private void checkBox2_CheckedChanged(object sender, EventArgs e)
//单端口扫描模式选择函数
private void button1_Click(object sender, EventArgs e)
//开始扫描按钮函数
private void button2_Click(object sender, EventArgs e)
//停止扫描按钮函数
public void wait()//扫描IP地址函数
public string State(int i)//判断端口状态函数
public string Service(int i)//返回开放端口服务函数
public void Scan(object Point)//扫描端口函数
//利用PingReply对象试探目标主机
Ping ping = new Ping(); //初始化一个Ping类实例
PingReply reply = ping.Send(IPAddress.Parse(ip + q), overTime); //调用同步Send方法发送消息,将返回结果保存至PingReply实例
if (reply.Status == IPStatus.Success) //如果能够Ping通,则说明远端主机开放
{
richTextBox1.Text += " IP地址: " + ip + q + "\n";
IPHostEntry host = Dns.GetHostEntry(ip + q); //取得该IP主机信息
richTextBox1.Text += " 主机名: "+ host.HostName + "\n";
}
else
{
listBox1.Items.Add(ip + q + " " + "-" + " " + "-" + " " + " - \n");
richTextBox1.Text += ip + q + " 不可达\n";
continue;
}
//Ping结束
public void Scan(object Point)
{
IPEndPoint IPPoint = (IPEndPoint)Point; //使用IPEndPoint类对象获取终结点的IP地址和端口号
try
{
TcpClient tcp = new TcpClient(); //创建一个TcpClient类
tcp.Connect(IPPoint); //调用Connect方法,使用指定的IP地址将客户端连接到TCP主机上
if (tcp.Connected) //如果连接上,证明此端口为开放状态
str.Add(Convert.ToString(IPPoint.Port));
}
catch
{
;
}
}
//IP存在,则开子线程开始端口扫描,端口数由textbox1,textbox2的差值决定
Thread[] tharr; //创建多线程
if (numThread < (portEnd - portStart + 1))
{
tharr = new Thread[portEnd - portStart + 1];
}
else
{
tharr = new Thread[numThread];
}
bool iscon = true; //第一个线程等待时间
for (int i = 0; i < tharr.Length; i++)
{
if (tharr[i] == null) //如果端口扫不到,说明未开放,跳过继续
continue;
while (tharr[i].IsAlive && iscon) //端口存在,对端口超时设置时间(目前200毫秒),一直等待此ip所有线程执行完毕才扫描下个ip
{
Thread.Sleep(200);
iscon = false; //第一个线程给200ms等待时间,其他线程由于同步执行的,所以没等待时间了,如果线程还没执行完,说明此端口不可达
}
}
运行程序启动端口扫描器,进入扫描器主界面:
(1)IP段端口扫描
当需要扫描的是IP地址段时,按界面提示输入IP地址段范围以及需要扫描的端口范围,然后可以选择只显示开放端口,完成后点击开始扫描按钮,测试结果如下:
测试的IP段为10.21.123.226-10.21.123.228,扫描的端口范围是0-300号端口,分配线程数为20,点击开始扫描按钮后等待数秒扫描完成。可以看到扫描各IP地址的端口的具体过程,以及扫描结果显示的端口状态和它们提供的服务。
(2)单主机单端口扫描模式
当需要扫描的是单主机时,选择单主机模式选项,端口范围也选择单端口模式,完成后点击开始扫描按钮,测试结果如下:
测试的IP地址为10.21.123.226,端口选择139端口,分配线程数为20.点击开始扫描按钮后等待数秒扫描完成。可以看到扫描结果为139端口状态为open,该端口提供的是NetBIOS/SMB服务。
(3)只显示开放端口
该扫描器还可以只显示开放端口以及它们所提供的服务,测试结果如下:
可以看到10.21.123.226的0-300端口中开放的只有80,135,139端口,提供的服务分别是HTTP协议代理服务,RPC(远程过程调用)服务,NetBIOS/SMB服务。
(4)错误提示
当不按照要求输入相应的IP地址和端口范围时,扫描器将出现错误提示,如下所示:
[1] 谢希仁.《计算机网络》[M].电子工业出版社,2013.6第6版
[2] 明日科技.《C#从入门到精通》[M].清华大学出版社,2012.9第3版
[3] 邓宇军.《C# 2.0程序设计教程》[M].清华大学出版社,2005.12第3版
[4] 肖微.《端口扫描技术的原理》[J].网络安全技术及应用,2006,(7):32-41