【pythonでパケットを分析できる】pysharkの基本的な使い方をご紹介

mieruka.link読者の皆様、こんばんわ!管理人の伊集院です。

今回は、Wiresharkやtcpdumpで取得したパケットキャプチャファイルをpythonで読み込んで分析できるpysharkのご紹介です。

pysharkを使えるようになると、、例えば以下のことを実現できます。

  • リアルタイムでパケットを監視し、特定のパケットを検知したらアラートを投げる等の自動化プログラムを開発
  • ネットワークデータの統計分析(ビッグデータ分析)

アイデア次第で使い方は無限大です。

本記事では、インストール方法と基本的な使い方、呼び出せるコマンドの調べ方をご紹介したいと思います。

pysharkインストール

本ブログで散々宣伝している、PC ENGINES apu4にインストールします。

筆者は、apu4にubuntu18.04.5 LTSをインストールしています。

$ sudo cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"

インストールは、以下に従ってください。

$ sudo add-apt-repository universe
$ sudo apt update
$ sudo apt install python3-pip
$ sudo pip3 install pyshark

パケットの収集

分析するためのpcapファイルを生成します。tcpdumpでもなんでもよいのですが、今回はtsharkを利用しました。

$ sudo tshark -w thshark.pcap
Running as user "root" and group "root". This could be dangerous.
sh: 1: /usr/bin/wireshark: not found
sh: 1: /usr/local/bin/wireshark: not found
Capturing on 'enp1s0'
1129 ^C  ・・・ 1129パケット取得して停止しています。

pysharkの実行

今回は、会話モードでpython3を実行してpysharkの動作確認をします。

$ sudo python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyshark  ・・・①pysharkのインポート
>>> cap = pyshark.FileCapture('thshark.pcap') ・・・②事前作成したpcapファイルの読み込み
>>> print(cap[0]) ・・・③1番目のキャプチャファイルの表示
Packet (Length: 142)
Layer ETH:
        Destination: d8:cb:8a:48:1a:7e
        Address: d8:cb:8a:48:1a:7e
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Source: a8:a1:59:6a:e4:b8
        Type: IPv4 (0x0800)
        Address: a8:a1:59:6a:e4:b8
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
Layer IP:
        0100 .... = Version: 4
        .... 0101 = Header Length: 20 bytes (5)
        Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)

非常に簡単に、pythonでpcapファイルを取り込み・表示することができることが分かっていただけたかと思います。

次に、201番目にキャプチャしたパケットがipv6だったのですが、このパケットを例にpytharkでどのような操作ができるかを実演したいと思います。

show()で成形してパケットを表示

201番目のパケットをshow()で成形して表示してみましょう。

>>> cap[200].show()
Layer ETH:
        Destination: a8:a1:59:6a:e4:b8
        Address: a8:a1:59:6a:e4:b8
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Source: xx:1a:fa:c3:2f:xx
        Type: IPv6 (0x86dd)
        Address: xx:1a:fa:c3:2f:xx
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
Layer IPV6:
        0110 .... = Version: 6
        .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
        .... .... .... 1010 0011 0100 1000 0100 = Flow Label: 0xa3484
        Payload Length: 227
        Next Header: TCP (6)
        Hop Limit: 54
        Source: xx06:4700:90:0:6cce:dc34:4151:e9xx
        Destination: 240d:1a:4db:7500:c075:eb8e:5ca6:391d
        Source GeoIP: US, ASN 13335, CLOUDFLARENET
        Source GeoIP Country: United States
        Source or Destination GeoIP Country: United States
        Source GeoIP ISO Two Letter Country Code: US
        Source or Destination GeoIP ISO Two Letter Country Code: US
        Source GeoIP AS Number: 13335

ここでLayerにIPV6とあります。dir()関数で、ipv6でどのような関数が利用できるかを調査することができます。

>>> dir(cap[200].ipv6)
['DATA_LAYER', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_all_fields', '_field_prefix', '_get_all_field_lines', '_get_all_fields_with_alternates', '_get_field_or_layer_repr', '_get_field_repr', '_layer_name', '_sanitize_field_name', 'addr', 'dst', 'dst_host', 'field_names', 'flow', 'geoip_asnum', 'geoip_city', 'geoip_country', 'geoip_country_iso', 'geoip_dst_asnum', 'geoip_dst_city', 'geoip_dst_country', 'geoip_dst_country_iso', 'geoip_dst_lat', 'geoip_dst_lon', 'geoip_dst_org', 'geoip_dst_summary', 'geoip_lat', 'geoip_lon', 'geoip_org', 'geoip_src_asnum', 'geoip_src_country', 'geoip_src_country_iso', 'geoip_src_lat', 'geoip_src_lon', 'geoip_src_org', 'geoip_src_summary', 'get', 'get_field', 'get_field_by_showname', 'get_field_value', 'hlim', 'host', 'ip_version', 'layer_name', 'nxt', 'plen', 'pretty_print', 'raw_mode', 'src', 'src_host', 'tclass', 'tclass_dscp', 'tclass_ecn', 'version']

それでは、geoip_asnumを実行してみましょう。

>>> print(cap[200].ipv6.geoip_asnum)
13335

このように、pythonで簡単にパーサーが開発できることが分かっていただけたかと思います。

Take it easy! パケット解析を楽しみましょう!!

(Visited 6,029 times, 12 visits today)
The following two tabs change content below.
【好きなもの】 インフラ技術が好き。古いものが好き。 【生きてきたフィールド】 システム運用、ソフトウェア開発、ミドルウェア検証、OSSサポート、プリセールスエンジニア、プロジェクトマネジメント 【このサイトでの役割】 サイト管理者。