#はじめに
前回([Python] Pythonとセキュリティ - ②Pythonで作るポートスキャニングツール)でPythonの概要や特徴について調べてみた。
今回はPythonを利用した簡単なポートスキャニングツールを作ってみよう。
また、ツールを利用することで不用意に動作しているサービスを確認して対応することが出来る。
情報を収集する行為である「Banner Grabbing」になるため、許可を得ていない対象に実施するのは犯罪です。当該の記事で問題が発生した場合、弊社では一切責任を負い兼ねますのでご了承ください。
#Port Scan(ポートスキャン)とは?
ポートスキャンは対象のサーバーもしくはネットワーク機器などに対してオープンしているポートを検索し、識別することである。オープンしているポートを確認することで、対象から起動しているサービスの確認ができ、攻撃者にとってはポートスキャンが攻撃のための事前準備とも言える。
Port Scanの種類は以下のものがある
- UDP Port Scan
- TCP Port Scan
- Connect Scan
- Half-open(SYN) Scan
- FIN / NULL / Xmas Scan
#Port Scan種類別特徴
##UDP Port Scan
UDP Scanの場合は、UDPプロトコルを利用してポートをスキャンする。ポートがオープンされている場合、対象からは応答はないが、クローズされている場合は、ICMPメッセージ(Destination Unreachable, Port Unreachable)の応答がある。但し、UDP Scanはルータやファイアウォールからパケットが損失される可能性が高いため、信頼性は低い。
##TCP Connect Scan(TCP Open Scan)
connect()関数を利用して、対象と3 Way-Handshakingを結び、オープンされているポートを確認するスキャン。信頼性が高くて、rootと権限がなくてもスキャンを行えるが、スキャンの速度が遅く、ログが残る。
##TCP Half-Open Scan(SYN Stealth Scan)
SYNスキャンとも呼ばれるHalf-Open Scanは、TCP Connect Scanとは違って、3 Way-Handshakingで完全なセッションは結ばず、SYNパケットのみ利用してポートを確認する。ログは残らないが、実施のため、root権限が必要である。
root権限が必要な理由?
TCPプロトコルのヘッダーの制御ビットの設定が必要なため、root権限じゃないとSYNスキャンは実行できない。
ログが残らない理由?
対象からSYN/ACKの応答を受信したら、応答としてACKではなく、RSTに設定したパケットを送信する。
RSTのパケットのため、通信が強制に終了されてしまい、通信設定が最後まで(セッションを結ぶ)行わなかったため、システムにログが残らない可能性が高い。
##FIN/NULL/Xmas Scan
三つのスキャンはFlagをFINに設定するTCP FIN Scan, 何も設定しないNULL Scan, FIN, PSH, HUGを同時に設定するXmas Scanがある。
それぞれ正常な通信ではないため、ログが残らない、対象がUNIX/Linux環境のみ使える、また、Open/Filter/エラーの結果が不明である特徴を持っている。
###FIN Scan
###NULL Scan
###Xmas Scan
#socketモジュールを利用してPythonでScanningツールを作ってみよう
socketモジュールをインポート後、connect()関数を利用し、IPとPort番号を指定したら、TCP通信を行う。send(), recv()関数を利用してデータの送信、受信が可能である。
import socket
s = socket.socket()
s.connect(('IPアドレス', ポート番号))
s.close()
#portがオープンされている場合
>>
#portがオープンされていない場合
Traceback (most recent call last):
File "C:/~", line 3, in <module>
s.connect(('127.0.0.1', 23))
ConnectionRefusedError: [WinError 10061] 対象のコンピューターによって拒否されたため、接続できませんでした。
エラーを解決するために、簡単な方法で「try」と「except」文を利用して成功と失敗に対してそれぞれ区別する。
import socket
try:
s = socket.socket()
s.connect(('IPアドレス', ポート番号))
print('success')
s.close()
except:
print('fail')
#portがオープンされている場合
>> success
#portがオープンされていない場合
>> fail
roop文を利用して範囲内のポート番号を自動で確認するように作る。
import socket
for port in range(1,101):
try:
s = socket.socket()
s.connect(('IPアドレス', port))
print('オープンされているポート:%d' % port)
s.close()
except: pass
>> オープンされているポート:22
>> オープンされているポート:80
1から100までのポートを確認するのは、時間がかかるので、Pythonのリストデータ型を利用して、主に使用されているポートのみスキャンしてみよう。
良く使用されるポート
20, 21(FTP) / 22(SSH) / 23(Telnet) / 25(SMTP) / 53(DNS) / 80(HTTP) / 110(POP3) / 123(NTP) / 443(HTTPS) / 1433(MSSQL) / 3306(MYSQL) / 1521(ORACLE) / 8080(ORACLE, TOMCAT) / 3389(RDP)
import socket
ports = [20, 21, 22, 23, 25, 53, 80, 110, 123, 443, 1433, 3306, 1521, 8080, 3389]
for port in ports:
try:
s = socket.socket()
s.connect(('IPアドレス', port))
print('オープンされているポート:%d' % port)
s.close()
except: pass
>> オープンされているポート:80
>> オープンされているポート:443
>> オープンされているポート:3306
>> オープンされているポート:8080
input()関数を利用して、ホストアドレスを入力し、ポートスキャニングを実施するコードを作ってみよう。
import socket
ports = [20, 21, 22, 23, 25, 53, 80, 110, 123, 443, 1433, 3306, 1521, 8080, 3389]
host = input('IPアドレス:')
for port in ports:
try:
s = socket.socket()
s.connect((host, port))
print('オープンされているポート:%d' % port)
s.close()
except: pass
>> IPアドレス:127.0.0.1
>> オープンされているポート:80
>> オープンされているポート:443
>> オープンされているポート:3306
>> オープンされているポート:8080
#まとめ
今回はPythonのsokectライブラリを利用して簡単なポートスキャニングツールを作ってみたが、これを実務的に使うためには色々修正が必要である。
但し、ポートスキャンの原理、またPythonで基本的なポートスキャンのツールが作れるので、担当者及び管理者はこの投稿を参考して、より安全なネットワーク環境の構築に役に立てればと思っている。
#記事まとめ
2020年02月14日 - [Python] Pythonとセキュリティ - ①Pythonとは