本記事は、オライリージャパンから発行されている「サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考(原題:Black Hat Python)」の学習メモとして、書籍ではPython2で書かれていますが、自分なりに解釈した上でPython3に書き直しをしています。
前回まででPythonのsocketライブラリを使ったTCPおよびUDP通信の基本について学びました。
今回はrawソケットを使った、パケットスニッファーの作成について学んでいきます。
rawソケットとは
前回までで使用した標準のソケットは、選択したトランスポート層であるTCPやUDPなどのプロトコルによってカプセル化され、データ送受信が行われます。
しかし、一つ下のネットワーク層であるIPやICMPなどのヘッダを含んだ「生(raw)のパケット」の送受信を行うにはrawソケットを使います。
プロミスキャスモードとは
今回作成するスクリプトでは、プロミスキャスと呼ばれるモードを有効化するようにコーディングしています。
通常は、LAN内に流れるパケットを受信したNIC(ネットワークインタフェースカード)がフレームを調べ、自分あてに届いたもの以外は破棄するようになっています。
しかし、このプロミスキャスモードを有効化したNICであれば、自分あて以外のパケットもすべて取り込むように動作するため、LANアナライザなどのネットワークモニタリングツールなどのフレームの内容を調べる用途で使われます。
パケットスニッファーの実装
それでは、パケットスニッファーを作成していきます。
以下がコードになります。
# sniffer.py import socket import os host = "192.168.2.1" if os.name == "nt": socket_protocol = socket.IPPROTO_IP else: socket_protocol = socket.IPPROTO_ICMP sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) sniffer.bind((host, 0)) sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL, 1) if os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) print(sniffer.recvfrom(65565)) if os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
- 5行目:リッスンするホストのIPアドレスを指定。
- 7行目:NICでパケットを盗聴するためのオプションを指定。システムがWindowsの場合、os.nameは"nt"となり、Linuxの場合は"posix"となります。
- 12行目:ソケットオブジェクトの作成。
- 15行目:パケットキャプチャしたデータにIPヘッダーを含めるオプションを指定。
- 17行目:システムがWIndowsであれば、ioctl()を使ってプロミスキャスモードを有効化する。
- 20行目:パケットを表示。
- 22行目:終了前にシステムがWindowsであれば、プロミスキャスモードを無効化する
動作確認
それでは、上記のスクリプトを実行してみます。
Windowsの場合、プロミスキャスモードを使うには管理者権限が必要なため、コマンドプロンプト(もしくはPowerShell)を管理者権限で起動します。
> python sniffer.py (b'E\x00\x00<b\x18\x00\x00\x80\x01\x00\x00\xc0\xa8\x02\x01\xc0\xa8\x02\x01\x08\x00L\xbe\x00\x01\x00\x9dabcdefghijklmnopqrstuvwabcdefghi', ('192.168.2.1', 0))
別ターミナルから自分あてに送信したpingの内容をキャプチャすることができました。
最後に
今回は、単一のパケットをキャプチャするだけのシンプルなスニッファーの作成について学びました。
次回ではIPヘッダーの各フィールドのデコード方法について学んでいきます。