Python 網路掃描器



埠掃描可以定義為一種監控技術,用於查詢特定主機上可用的開放埠。網路管理員、滲透測試人員或駭客可以使用此技術。我們可以根據我們的需求配置埠掃描器,以從目標系統獲取最大資訊。

現在,考慮一下執行埠掃描後我們可以獲得的資訊:

  • 有關開放埠的資訊。

  • 有關每個埠上執行的服務的資訊。

  • 有關目標主機作業系統和 MAC 地址的資訊。

埠掃描就像一個小偷,想要進入一所房子,檢查每一扇門和窗戶,看看哪些是開啟的。如前所述,用於網際網路通訊的 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 響應。

Port Scanner using ICMP

上述傳送 ICMP 請求的過程也稱為 ping 掃描,由作業系統的 ping 命令提供。

Ping 掃描的概念

實際上,在某種意義上,ping 掃描也被稱為 ping 掃描。唯一的區別是 ping 掃描是查詢特定網路範圍內多個機器可用性的過程。例如,假設我們想要測試完整的 IP 地址列表,然後使用 ping 掃描,即作業系統的 ping 命令,逐個掃描 IP 地址將非常耗時。這就是我們需要使用 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)

上述指令碼分為三個部分。它首先選擇要進行 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)

上述指令碼分為三個部分。它選擇要進行 ping 掃描的 IP 地址範圍,將其分成多個部分。接下來是使用一個用於掃描地址的函式,該函式進一步使用套接字。隨後,它給出有關主機和完成掃描過程所需時間的響應。result = 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)

在上述指令碼中,我們需要匯入 threading 模組,該模組內置於 Python 包中。我們正在使用執行緒鎖定概念,thread_lock = threading.Lock() 以避免一次進行多次修改。基本上,threading.Lock() 將允許單個執行緒一次訪問變數。因此,不會發生雙重修改。

隨後,我們定義一個 threader() 函式,該函式將從 worker for 迴圈中獲取工作(埠)。然後呼叫 portscan() 方法連線到埠並列印結果。埠號作為引數傳遞。任務完成後,將呼叫 q.task_done() 方法。

現在,在執行上述指令碼後,我們可以看到掃描 50 到 500 個埠的速度差異。它僅花費了 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
廣告