Pythonでポートスキャンしてみよう

アドベントカレンダー, 未分類

Pythonでポートスキャンしてみよう

はじめに

この記事は7日目のアドベントカレンダーです.

こんにちは,大学2年生の松田雄飛です.
初めての記事投稿になります.
以前からPythonと情報セキュリティについて勉強してみたいと考えていて,今回の記事制作に至りました.

※ 敵の手の内,つまり攻撃方法を知ることで防ぐ方法を知ってもらうためのものなので他人に攻撃をしかけるなどの行為は遠慮してください.

目次

  1. 環境構築
  2. 攻撃の事前調査
  3. ソケット調査
  4. ポートスキャン

1.環境構築

本記事ではPython3を使ってコードを実装しています.Python2では動作しない可能性があるので,Python3を使ってください.
下記のコマンドをターミナルで入力すればPython3がインストールされます.
brew install python3
Python3でコードを実行する方法はターミナルで
Python3 ○○○.py
と入力するだけです.
試しにHello.pyというファイルを作成し,下記のコードを入力し,実行してみましょう.

print("HelloWorld")

もし,Python3がインストール,実行できない方は下記の記事を参考にしてください.
Python3のインストール方法

2.攻撃の事前調査

  1. 対象サーバを絞り込む
  2. ポートスキャンを行う
  3. バナーチェックを行う
  4. そのほかの情報収集

今回はPythonでポートスキャンをやってみようと思います.

3.ソケット通信

Pythonからソケットを扱うので,標準の,socketライブラリを使用します.その前にソケット通信とはなにか知っておく必要があります.ソケット通信とは開発者がプロトコルの詳しい仕様や具体的な通信手段を知らなくても簡単にネットワーク通信を行うプログラムを作ることができます.
詳しくはこちら

import socket
sock = scket.socket(socket.AF_INET,socket.SOCK_STREAM)

上記のコードをPythonで記述し実行するとソケットを作ることができます.1行目でimport文を使ってsocketライブラリをインポートした後,2行目で新しいソケットを作成しています.
TCP/IP通信を行いたいときは,第1引数にIPv4プロトコルファミリを表すAF_INET,第2引数にストリーム通信を表すSOCK_STREAMを指定します.

4.ポートスキャン

TCP/IP通信において,コンピュータが使用するプログラムを識別する目の番号にポート番号というものがあります.ポート番号について詳しく知りたい方はポート番号とは,ポート番号の必要性を読んでみてください.

開放されているポートを探すことをポートスキャンといいます.サイバー攻撃を行う前の準備段階として実施される作業です.
ポートスキャンの種類もたくさんあります.
ポートスキャンをされたからといって直接的な被害を受けることはありません.しかし,ポートスキャンを行われることで色々な情報を与えてしまう可能性があります.

ポートスキャンを行われることで与える情報

  • 開いているポート番号
  • 閉じているポート番号
  • FW(ファイアウォール)によってフィルタリングされているポート情報
  • 開いているポートで稼働しているサービス(HTTPやFTP)の情報
  • 開いているポートのサービスに関する情報(バージョンなど)
  • OSに関する情報

ポートスキャンによる被害例

  • 情報漏えい
  • マルウェアの感染
  • システムのハッキング
  • 踏み台/DDoS攻撃の加担

ポート番号とは,TCP/IP通信において,コンピュータが通信に使用するプログラムを識別するための番号のことであり,0番~65535番までありますが,0番から1023番まではすでに稼働しているサービスに割り振られています.1023番まではWell-known(ウェルノウン)ポートといいます.
また,1024番〜49152番は登録済みポート,49152番〜65535番まではプライベートポートといいます.プライベートポートは自由に利用することができます.

nmapやzenmapなど既に用意されているポートスキャナもあるので興味があれば是非こちらも試してください.
nmap

まずはPythonからポートの状態を確認します.
ポートの状態を調べるときは,socketライブラリのconnectメソッドを使います.ポートが空いている時はそのポートに接続可能ということなので,connectメソッドは成功し,逆にポートが閉じているときは接続できずにエラーが発生します.

以下のコード実行すれば,ローカルホストのTCP/7000番ポートに接続を試みことができます.

import socket
sock = socket.socket()
sock.connect
sock.connect(('127.0.0.1',7000))

接続に失敗すると以下のエラー文が返ってきます.
'127.0.0.1’とは簡潔に述べると,自分自身を指すIPアドレスです.
はじめにも述べていますが,他者にポートスキャンをするのは非常に迷惑なので自分自身にポートスキャンをしましょう.

...省略...
socket.error: [Errno 61] Connection refused

これを調べたい全てのポートに対して行うようなPythonプログラムを書けば,ポートスキャンツールの完成です.
ただ,connectメソッドは失敗した時にエラーを返すので,connectメソッドの代わりにconnect_exというメソッドを使います.

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(("127.0.0.1",7000))
if result == 0:
    print("Port is open")
else:
    print("Port is not open")

connect_exメソッドはやっていることはconnectメソッドと同じなのですが,結果の返し方が異なり,接続に成功したときは0の値を返すので,それをif文を使い表示させます.
すると先程のエラー文がPort is not openという文字列になって返ってきます.

最後にsock.connect_exの部分を変数にして,for文で実行すると下記のコードでは1~50000番までポートスキャンを実行します.

import socket
host = "127.0.0.1"
for port in range(1,50000):
    #target_host のポート番号portに接続を試行
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = sock.connect_ex((host, port))
    sock.close()
    #socket.connect_ex は成功すると0を返す
    if result == 0:
        print("Port %d open!" % (port))

上記のコードでポートスキャンは完了です.

ポートが開いていない場合は自分でポートを開放して試してみましょう.
もしくは,rangeの値を変えてみてください.

ポートスキャンではサーバー上にアクセスログが痕跡として残ってしまします.それを回避するためにステルススキャンというものがあるのも覚えておくといいかもしれません.

おわりに

記事を最後まで閲覧して頂きありがとうございます.
ポートスキャンのみでは攻撃は行えませんし,犯罪にもなりません.しかしサイバー攻撃の前にはこのような事前調査が行われているんだな程度で思っていてください.

次回予告:
やめて! ポートスキャンで、開いているポート番号がバレたら、闇のゲームでモンスターと繋がってる城之内の精神まで燃え尽きちゃう!
お願い、死なないで城之内!
あんたが今ここで倒れたら、ポートスキャンだけで何がわかるの?
ライフはまだ残ってる。ここを耐えれば、XSSを勉強できるんだから!

次回『XSSの記事投稿! 城之内 死す』 デュエルスタンバイ!