我们都知道,TCP协议基于三次握手,是稳定可靠的数据传输协议,传统的端口扫描都是基于以下几种模式。
第一种: 通过PING ICMP数据报文来探测远程主机是否存活 , 这种方式可以同时探测出远程链路的延迟和粗略的判断出远程主机软件操作系统名称, 但是误差很大,基于TTL,如小于32一般为win95/98/me , 一般大于128小于255一般为Unix 或者网络设备。这种方法因为工作在网络层,所以可以被防火墙或者网络设备欺骗或者直接无响应。
第二种:这种就相比较上一种,比较高级了,利用了TCP协议的RST标志位,远程主机回应RST的值和WINDOW窗口值可以判断出操作系统的类型,当然这种扫描只对特定的几个操作系统版本有回应。
第三种:这种就比上面两种高级了,利用TCP socket SocketType.Stream 流式套接口协议,TCP两次握手,即可判断出远程主机是否开放了特定端口,当然这种方式无法判断操作系统的类型和版本。
对于判断操作系统版本的方法,可以用过NETBIOS 和 SNMP 团体默认关键字 Public Private 猜解来获取。
今天我们演示一下C# 纯命令行多线程扫描指定范围主机的方法 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter StartIp:");
string StartIp= Console.ReadLine();
Console.WriteLine("Please Enter EndIp:");
string EndIp = Console.ReadLine();
ThreadPool.SetMaxThreads(1024,1024);
List<string> IpList = GetIpDistance(StartIp,EndIp);
foreach(string IpInfo in IpList)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckPortOpen), IpInfo);
}
Console.ReadKey();
}
public static void CheckPortOpen(object Ip)
{
IPAddress ip = IPAddress.Parse((string)Ip);
for (int i = 0; i < 65535; i++)
{
IPEndPoint point = new IPEndPoint(ip,i);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(point);
socket.Close();
Console.WriteLine(string.Format("Ip:{0} , Port:{1} is Open", Ip,i));
}
catch
{
//Console.WriteLine(string.Format("Ip:{0} , Port:{1} is Close", Ip,i));
}
}
}
public static List<string> GetIpDistance(string StartIp, string EndIp)
{
uint IStartIp = IpInt(StartIp);
uint IEndIp = IpInt(EndIp);
List<string> IpListInfo = new List<string>();
if (IEndIp >= IStartIp)
{
for (uint ip = IStartIp; ip <= IEndIp; ip++)
{
IpListInfo.Add(IntIp(ip));
}
}
return IpListInfo;
}
public static uint IpInt(string ipStr)
{
string[] ip = ipStr.Split('.');
uint ipcode = 0xFFFFFF00 | byte.Parse(ip[3]);
ipcode = ipcode & 0xFFFF00FF | (uint.Parse(ip[2]) << 0x8);
ipcode = ipcode & 0xFF00FFFF | (uint.Parse(ip[1]) << 0x10);
ipcode = ipcode & 0x00FFFFFF | (uint.Parse(ip[0]) << 0x18);
return ipcode;
}
public static string IntIp(uint ipcode)
{
byte addr1 = (byte)((ipcode & 0xFF000000) >> 0x18);
byte addr2 = (byte)((ipcode & 0x00FF0000) >> 0x10);
byte addr3 = (byte)((ipcode & 0x0000FF00) >> 0x8);
byte addr4 = (byte)(ipcode & 0x000000FF);
return string.Format("{0}.{1}.{2}.{3}", addr1, addr2, addr3, addr4);
}
}
}
运行结果如下:
提示输入开始IP和结束IP范围,会多线程扫描该网段每一个主机的每一个端口。
利用了Tcp Sokect 流式套接口判断远程端口是否开启,和telnet 主机:端口 一个原理。