Python Network Scanner

การสแกนพอร์ตอาจถูกกำหนดให้เป็นเทคนิคการเฝ้าระวังซึ่งใช้เพื่อค้นหาพอร์ตที่เปิดอยู่บนโฮสต์เฉพาะ ผู้ดูแลระบบเครือข่ายผู้ทดสอบการเจาะระบบหรือแฮ็กเกอร์สามารถใช้เทคนิคนี้ได้ เราสามารถกำหนดค่าเครื่องสแกนพอร์ตตามความต้องการของเราเพื่อรับข้อมูลสูงสุดจากระบบเป้าหมาย

ตอนนี้ให้พิจารณาข้อมูลที่เราจะได้รับหลังจากเรียกใช้การสแกนพอร์ต -

  • ข้อมูลเกี่ยวกับพอร์ตที่เปิดอยู่

  • ข้อมูลเกี่ยวกับบริการที่ทำงานบนแต่ละพอร์ต

  • ข้อมูลเกี่ยวกับ OS และที่อยู่ MAC ของโฮสต์เป้าหมาย

การสแกนพอร์ตก็เหมือนกับขโมยที่ต้องการเข้าไปในบ้านโดยตรวจสอบประตูและหน้าต่างทุกบานเพื่อดูว่าบานไหนเปิดอยู่ ตามที่กล่าวไว้ก่อนหน้านี้ชุดโปรโตคอล TCP / IP ใช้สำหรับการสื่อสารผ่านอินเทอร์เน็ตประกอบด้วยสองโปรโตคอล ได้แก่ TCP และ UDP โปรโตคอลทั้งสองมีพอร์ต 0 ถึง 65535 ตามที่แนะนำให้ปิดพอร์ตที่ไม่จำเป็นของระบบของเราเสมอดังนั้นโดยพื้นฐานแล้วมีประตูมากกว่า 65000 ประตู (พอร์ต) ให้ล็อค พอร์ต 65535 เหล่านี้สามารถแบ่งออกเป็นสามช่วงต่อไปนี้ -

  • ระบบหรือพอร์ตที่รู้จักกันดี: ตั้งแต่ 0 ถึง 1023

  • ผู้ใช้หรือพอร์ตที่ลงทะเบียน: ตั้งแต่ 1024 ถึง 49151

  • พอร์ตไดนามิกหรือพอร์ตส่วนตัว: ทั้งหมด> 49151

พอร์ตสแกนเนอร์โดยใช้ Socket

ในบทที่แล้วเราได้พูดถึงซ็อกเก็ตคืออะไร ตอนนี้เราจะสร้างเครื่องสแกนพอร์ตอย่างง่ายโดยใช้ซ็อกเก็ต ต่อไปนี้เป็นสคริปต์ 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 ใด ๆ โดยไม่ได้รับอนุญาตเป็นลายลักษณ์อักษรจากเจ้าของเซิร์ฟเวอร์หรือคอมพิวเตอร์ที่คุณกำหนดเป้าหมายอย่างชัดเจน การสแกนพอร์ตคล้ายกับการไปบ้านของใครบางคนและตรวจสอบประตูและหน้าต่างของพวกเขา นั่นคือเหตุผลที่แนะนำให้ใช้พอร์ตสแกนเนอร์บน localhost หรือเว็บไซต์ของคุณเอง (ถ้ามี)

เอาต์พุต

สคริปต์ด้านบนสร้างผลลัพธ์ต่อไปนี้ -

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 ข้างต้นเรียกอีกอย่างว่าการสแกน ping ซึ่งจัดทำโดยคำสั่ง ping ของระบบปฏิบัติการ

แนวคิดของ Ping Sweep

จริงๆแล้วในแง่หนึ่งหรืออย่างอื่นการกวาด ping เรียกอีกอย่างว่าการกวาด ping ข้อแตกต่างเพียงอย่างเดียวคือการกวาด ping เป็นขั้นตอนในการค้นหาความพร้อมใช้งานของเครื่องมากกว่าหนึ่งเครื่องในช่วงเครือข่ายเฉพาะ ตัวอย่างเช่นสมมติว่าเราต้องการทดสอบรายการที่อยู่ IP ทั้งหมดจากนั้นโดยใช้การสแกน ping กล่าวคือคำสั่ง ping ของระบบปฏิบัติการจะใช้เวลานานมากในการสแกนที่อยู่ IP ทีละรายการ นั่นคือเหตุผลที่เราต้องใช้สคริปต์กวาด ping ต่อไปนี้เป็นสคริปต์ Python สำหรับค้นหาโฮสต์สดโดยใช้การกวาด ping -

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 กวาดตามระบบปฏิบัติการและสุดท้ายคือการตอบสนองเกี่ยวกับโฮสต์และเวลาที่ใช้ในการดำเนินการสแกนให้เสร็จสิ้น

เอาต์พุต

สคริปต์ด้านบนสร้างผลลัพธ์ต่อไปนี้ -

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 โฮสต์ต้องดำเนินการจับมือสามทาง ทำตามขั้นตอนเหล่านี้เพื่อดำเนินการ -

Step 1 − Packet with SYN flag set

ในขั้นตอนนี้ระบบที่พยายามเริ่มต้นการเชื่อมต่อจะเริ่มต้นด้วยแพ็กเก็ตที่มีการตั้งค่าสถานะ SYN

Step 2 − Packet with SYN-ACK flag set

ในขั้นตอนนี้ระบบเป้าหมายจะส่งคืนแพ็กเก็ตที่มีชุดค่าสถานะ SYN และ ACK

Step 3 − Packet with ACK flag set

ในที่สุดระบบเริ่มต้นจะส่งคืนแพ็กเก็ตไปยังระบบเป้าหมายดั้งเดิมด้วยชุดค่าสถานะ ACK

อย่างไรก็ตามคำถามที่เกิดขึ้นคือถ้าเราสามารถสแกนพอร์ตโดยใช้ ICMP echo request และวิธีตอบกลับ (ping Sweep scanner) แล้วทำไมเราถึงต้องใช้ TCP scan? เหตุผลหลักที่อยู่เบื้องหลังคือสมมติว่าถ้าเราปิดคุณสมบัติการตอบกลับ 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 กวาดสแกนโดยแยกเป็นส่วน ๆ ตามด้วยการใช้ฟังก์ชันสำหรับการสแกนที่อยู่ซึ่งจะใช้ซ็อกเก็ตเพิ่มเติม ต่อมาจะให้คำตอบเกี่ยวกับโฮสต์และเวลาที่ใช้ในการดำเนินการสแกนให้เสร็จสิ้น ผลลัพธ์ = 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

Threaded Port Scanner เพื่อเพิ่มประสิทธิภาพ

ดังที่เราได้เห็นในกรณีข้างต้นการสแกนพอร์ตอาจช้ามาก ตัวอย่างเช่นคุณสามารถดูเวลาที่ใช้ในการสแกนพอร์ตตั้งแต่ 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 () หนึ่งฟังก์ชันที่จะดึงงาน (พอร์ต) จากผู้ปฏิบัติงานสำหรับการวนซ้ำ จากนั้นเรียกเมธอด portscan () เพื่อเชื่อมต่อกับพอร์ตและพิมพ์ผลลัพธ์ หมายเลขพอร์ตถูกส่งผ่านเป็นพารามิเตอร์ เมื่องานเสร็จสมบูรณ์จะเรียกเมธอด q.task_done ()

หลังจากเรียกใช้สคริปต์ด้านบนแล้วเราจะเห็นความแตกต่างของความเร็วในการสแกนพอร์ต 50 ถึง 500 ใช้เวลาเพียง 1.3589999675750732 วินาทีซึ่งน้อยกว่า 452.3990001678467 เวลาที่ใช้โดยเครื่องสแกนพอร์ตซ็อกเก็ตในการสแกนจำนวนพอร์ตเดียวกันของ localhost

เอาต์พุต

สคริปต์ด้านบนสร้างผลลัพธ์ต่อไปนี้ -

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