📜  Python网络扫描仪

📅  最后修改于: 2020-12-06 10:31:53             🧑  作者: Mango


端口扫描可以定义为一种监视技术,用于定位特定主机上可用的开放端口。网络管理员,渗透测试人员或黑客可以使用此技术。我们可以根据我们的要求配置端口扫描器,以从目标系统获取最大信息。

现在,考虑我们在运行端口扫描后可以获得的信息-

  • 有关开放端口的信息。

  • 有关在每个端口上运行的服务的信息。

  • 有关目标主机的OS和MAC地址的信息。

港口扫描就像一个小偷,他想通过检查每扇门和窗户以查看哪些门打开来进入房屋。如前所述,用于通过Internet进行通信的TCP / IP协议套件由TCP和UDP这两个协议组成。两种协议都有0到65535端口。因此,从本质上讲,总是建议关闭系统不必要的端口,因此有65000多个门(端口)需要锁定。这些65535端口可以分为以下三个范围-

  • 系统或知名端口:0到1023

  • 用户或注册端口:从1024到49151

  • 动态或专用端口:所有> 49151

使用套接字的端口扫描器

在上一章中,我们讨论了套接字是什么。现在,我们将使用套接字构建一个简单的端口扫描程序。以下是使用套接字的端口扫描程序的Python脚本-

from socket import *
import time
startTime = time.time()

if __name__ == '__main__':
   target = input('Enter the host to be scanned: ')
   t_IP = gethostbyname(target)
   print ('Starting scan on host: ', t_IP)
   
   for i in range(50, 500):
      s = socket(AF_INET, SOCK_STREAM)
      
      conn = s.connect_ex((t_IP, i))
      if(conn == 0) :
         print ('Port %d: OPEN' % (i,))
      s.close()
print('Time taken:', time.time() - startTime)

当我们运行上面的脚本时,它将提示您输入主机名,您可以提供任何主机名,例如任何网站的名称,但是请小心,因为端口扫描可以被视为或被视为犯罪。未经目标服务器或计算机所有者的明确书面许可,我们绝对不应针对任何网站或IP地址执行端口扫描程序。端口扫描类似于去某人的房屋并检查他们的门窗。因此,建议在本地主机或您自己的网站(如果有)上使用端口扫描程序。

输出

上面的脚本生成以下输出-

Enter the host to be scanned: localhost
Starting scan on host: 127.0.0.1
Port 135: OPEN
Port 445: OPEN
Time taken: 452.3990001678467

输出显示,在50到500的范围内(如脚本中所提供),此端口扫描程序找到了两个端口-端口135和445打开。我们可以更改此范围,并可以检查其他端口。

使用ICMP的端口扫描程序(网络中的实时主机)

ICMP不是端口扫描,而是用于ping远程主机以检查主机是否已启动。当我们必须检查网络中的多个活动主机时,此扫描很有用。它涉及向主机发送ICMP ECHO请求,如果该主机处于活动状态,它将返回ICMP ECHO回复。

使用ICMP的端口扫描程序

上面发送ICMP请求的过程也称为ping扫描,由操作系统的ping命令提供。

平扫的概念

实际上,从某种意义上讲,ping扫描也称为ping扫描。唯一的区别是ping扫描是在特定网络范围内查找多台计算机可用性的过程。例如,假设我们要测试IP地址的完整列表,然后使用ping扫描,即操作系统的ping命令,一次一扫描IP地址将非常耗时。这就是为什么我们需要使用ping扫描脚本的原因。以下是使用ping扫描查找实时主机的Python脚本-

import os
import platform

from datetime import datetime
net = input("Enter the Network Address: ")
net1= net.split('.')
a = '.'

net2 = net1[0] + a + net1[1] + a + net1[2] + a
st1 = int(input("Enter the Starting Number: "))
en1 = int(input("Enter the Last Number: "))
en1 = en1 + 1
oper = platform.system()

if (oper == "Windows"):
   ping1 = "ping -n 1 "
elif (oper == "Linux"):
   ping1 = "ping -c 1 "
else :
   ping1 = "ping -c 1 "
t1 = datetime.now()
print ("Scanning in Progress:")

for ip in range(st1,en1):
   addr = net2 + str(ip)
   comm = ping1 + addr
   response = os.popen(comm)
   
   for line in response.readlines():
      if(line.count("TTL")):
         break
      if (line.count("TTL")):
         print (addr, "--> Live")
         
t2 = datetime.now()
total = t2 - t1
print ("Scanning completed in: ",total)

上面的脚本分为三个部分。首先,通过将IP地址分为几部分来选择要进行ping扫描的IP地址范围。然后使用函数,该函数将根据操作系统选择用于ping扫描的命令,最后它给出有关主机和完成扫描过程所用时间的响应。

输出

上面的脚本生成以下输出-

Enter the Network Address: 127.0.0.1
Enter the Starting Number: 1
Enter the Last Number: 100

Scanning in Progress:
Scanning completed in: 0:00:02.711155

上面的输出没有显示活动端口,因为防火墙已打开并且ICMP入站设置也被禁用。更改这些设置后,我们可以获得输出中提供的1到100范围内的活动端口列表。

使用TCP扫描的端口扫描器

要建立TCP连接,主机必须执行三向握手。请按照以下步骤执行操作-

步骤1-设置了SYN标志的数据包

在此步骤中,尝试启动连接的系统从设置了SYN标志的数据包开始。

步骤2-设置了SYN-ACK标志的数据包

在此步骤中,目标系统返回带有SYN和ACK标志集的数据包。

步骤3-设置了ACK标志的数据包

最后,启动系统将把设置了ACK标志的数据包返回到原始目标系统。

但是,这里出现的问题是,如果我们可以使用ICMP回显请求和应答方法(ping扫描器)进行端口扫描,那么为什么需要TCP扫描呢?其背后的主要原因是,假设如果我们关闭ICMP ECHO答复功能或对ICMP数据包使用防火墙,则ping扫描扫描程序将无法工作,我们需要TCP扫描。

import socket
from datetime import datetime
net = input("Enter the IP address: ")
net1 = net.split('.')
a = '.'

net2 = net1[0] + a + net1[1] + a + net1[2] + a
st1 = int(input("Enter the Starting Number: "))
en1 = int(input("Enter the Last Number: "))
en1 = en1 + 1
t1 = datetime.now()

def scan(addr):
   s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   socket.setdefaulttimeout(1)
   result = s.connect_ex((addr,135))
   if result == 0:
      return 1
   else :
      return 0

def run1():
   for ip in range(st1,en1):
      addr = net2 + str(ip)
      if (scan(addr)):
         print (addr , "is live")
         
run1()
t2 = datetime.now()
total = t2 - t1
print ("Scanning completed in: " , total)

上面的脚本分为三个部分。它通过将IP地址分为几部分来选择要进行ping扫描的IP地址范围。接下来是使用扫描地址的函数,该功能进一步使用了套接字。稍后,它将给出有关主机和完成扫描过程所用时间的响应。结果= s。 connect_ex((addr,135))语句返回错误指示符。如果操作成功,则错误指示符为0,否则为errno变量的值。在这里,我们使用端口135。该扫描仪适用于Windows系统。在这里可以使用的另一个端口是445(Microsoft-DSActive Directory),通常处于打开状态。

输出

上面的脚本生成以下输出-

Enter the IP address: 127.0.0.1
Enter the Starting Number: 1
Enter the Last Number: 10

127.0.0.1 is live
127.0.0.2 is live
127.0.0.3 is live
127.0.0.4 is live
127.0.0.5 is live
127.0.0.6 is live
127.0.0.7 is live
127.0.0.8 is live
127.0.0.9 is live
127.0.0.10 is live
Scanning completed in: 0:00:00.230025

螺纹端口扫描仪可提高效率

正如在以上情况中所看到的那样,端口扫描可能非常慢。例如,使用套接字端口扫描器时,扫描端口从50到500所需的时间为452.3990001678467。为了提高速度,我们可以使用线程。以下是使用线程的端口扫描程序的示例-

import socket
import time
import threading

from queue import Queue
socket.setdefaulttimeout(0.25)
print_lock = threading.Lock()

target = input('Enter the host to be scanned: ')
t_IP = socket.gethostbyname(target)
print ('Starting scan on host: ', t_IP)

def portscan(port):
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   try:
      con = s.connect((t_IP, port))
      with print_lock:
         print(port, 'is open')
      con.close()
   except:
      pass

def threader():
   while True:
      worker = q.get()
      portscan(worker)
      q.task_done()
      
q = Queue()
   startTime = time.time()
   
for x in range(100):
   t = threading.Thread(target = threader)
   t.daemon = True
   t.start()
   
for worker in range(1, 500):
   q.put(worker)
   
q.join()
print('Time taken:', time.time() - startTime)

在上面的脚本中,我们需要导入线程模块,该模块内置在Python包中。我们使用线程锁定概念thread_lock = threading.Lock()来避免一次进行多次修改。基本上,threading.Lock()将允许单个线程一次访问该变量。因此,不会发生双重修改。

稍后,我们定义了一个threader()函数,该函数将从worker的循环中获取工作(端口)。然后调用portscan()方法以连接到端口并打印结果。端口号作为参数传递。任务完成后,将调用q.task_done()方法。

现在,在运行上述脚本之后,我们可以看到扫描50到500个端口的速度差异。套接字端口扫描程序扫描相同数量的localhost端口仅花费了1.3589999675750732秒,这远远少于452.3990001678467。

输出

上面的脚本生成以下输出-

Enter the host to be scanned: localhost
Starting scan on host: 127.0.0.1
135 is open
445 is open
Time taken: 1.3589999675750732