Pythonネットワークスキャナー
ポートスキャンは、特定のホストで使用可能な開いているポートを見つけるために使用される監視技術として定義できます。ネットワーク管理者、侵入テスター、またはハッカーはこの手法を使用できます。要件に応じてポートスキャナーを構成し、ターゲットシステムから最大の情報を取得できます。
ここで、ポートスキャンを実行した後に取得できる情報について考えてみましょう。
開いているポートに関する情報。
各ポートで実行されているサービスに関する情報。
ターゲットホストのOSおよびMACアドレスに関する情報。
ポートスキャンは、すべてのドアと窓をチェックして、どれが開いているかを確認することで家に入ろうとする泥棒のようなものです。前に説明したように、インターネットを介した通信に使用されるTCP / IPプロトコルスイートは、TCPとUDPの2つのプロトコルで構成されています。どちらのプロトコルにも0〜65535のポートがあります。したがって、システムの不要なポートを閉じることを常にお勧めします。したがって、基本的に、ロックするドア(ポート)は65000を超えます。これらの65535ポートは、次の3つの範囲に分けることができます。
システムまたは既知のポート: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)
上記のスクリプトを実行すると、ホスト名の入力を求められます。任意のWebサイトの名前など、任意のホスト名を指定できますが、ポートスキャンは犯罪と見なされるか、犯罪と解釈される可能性があるため、注意が必要です。対象のサーバーまたはコンピューターの所有者からの書面による明示的な許可なしに、WebサイトまたはIPアドレスに対してポートスキャナーを実行しないでください。ポートスキャンは、誰かの家に行ってドアや窓をチェックするのと似ています。そのため、ローカルホストまたは独自のWebサイト(存在する場合)でポートスキャナーを使用することをお勧めします。
出力
上記のスクリプトは次の出力を生成します-
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の範囲で、このポートスキャナーが2つのポート(ポート135と445)が開いていることを検出したことを示しています。この範囲を変更して、他のポートを確認できます。
ICMPを使用したポートスキャナー(ネットワーク内のライブホスト)
ICMPはポートスキャンではありませんが、リモートホストにpingを実行して、ホストが稼働しているかどうかを確認するために使用されます。このスキャンは、ネットワーク内の多数のライブホストをチェックする必要がある場合に役立ちます。これには、ICMP ECHO要求をホストに送信することが含まれ、そのホストが稼働している場合は、ICMPECHO応答が返されます。
ICMP要求を送信する上記のプロセスは、pingスキャンとも呼ばれ、オペレーティングシステムのpingコマンドによって提供されます。
Pingスイープの概念
実際には、ある意味で、pingスイープはpingスイープとも呼ばれます。唯一の違いは、pingスイープは、特定のネットワーク範囲で複数のマシンの可用性を見つける手順であるということです。たとえば、IPアドレスの完全なリストをテストしたい場合、pingスキャン、つまりオペレーティングシステムのpingコマンドを使用して、IPアドレスを1つずつスキャンするのは非常に時間がかかります。そのため、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)
上記のスクリプトは3つの部分で機能します。まず、IPアドレスの範囲を部分に分割してpingスイープスキャンを選択します。続いて、オペレーティングシステムに応じて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接続を確立するには、ホストは3ウェイハンドシェイクを実行する必要があります。次の手順に従って、アクションを実行します-
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エコー要求および応答方法(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)
上記のスクリプトは3つの部分で機能します。部分に分割することにより、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()は、単一のスレッドが一度に変数にアクセスできるようにします。したがって、二重の変更は発生しません。
後で、ワーカーのforループから作業(ポート)をフェッチする1つのthreader()関数を定義します。次に、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