こんにちは!この春フロムスクラッチに入社した新人エンジニアのおんじです!
今回のフロムスクラッチ開発ブログでは「CTFのバイナリ解析から学ぶセキュリティとハッキング」に続いて、パケット解析編の勉強会について書きたいと思います。
※CTFバイナリ解析編のバックナンバーは、こちらからどうぞ!
1.CTFとは?
CTFとは情報技術に関する問題に対して適切な形で対処することで、「フラグ(Flag)」と呼ばれる得点対象の文字列を取得することによって、得られた得点で勝敗を決める大会です。”Capture The Flag”の頭文字をとってCTFといいます。国内ではSECCON CTFが有名です。(CTFについては、こちらの記事で詳しく触れています。)
2.ネットワークプロトコルとパケット
パケット解析では、ネットワークを流れる通信を分析して、どのようなプロトコルでどのような要素を扱った通信を行っているのかを解明します。そのため、まずは前提のネットワークプロトコルの知識を確認していきます。
ネットワークプロトコルとは、ネットワーク上での通信に関する規約を定めたものです。TCP/IPのモデルによると、これは以下のような階層構造になっています。
これは、階層間の依存を無くし、プロトコルの開発やメンテナンスを容易に行えるようにすることを目的とした構造になっています。
何らかのデータを送信する際には、上記のそれぞれの階層で、そのプロトコルに必要な情報を渡されたデータの先頭に付与し、次の階層に渡します。この付与した情報をヘッダと呼び、このヘッダを付与する動作をカプセル化と呼びます。
逆に、データを受信した際には、それぞれの階層でこのヘッダを解釈し、削除した後に次の階層に渡していきます。
今回扱うパケットは、一般的には、インターネット層のデータのことを指します。しかし、パケット解析を行う際には、ネットワークインターフェース層のヘッダとデータも解析します。この部分は一般的にはフレームと呼ばれますが、便宜上この記事では上図の太枠で囲われた部分をパケットと定義します。
3.pcapファイル
ではパケットに関する前提を確認した所で、実際にパケットの解析に進んでいきたいと思います。ここではWiresharkと呼ばれるGUIのネットワークパケット・プロトコル解析ツールを使用していきます。
※OSはUbuntu 16.04.4 、Wiresharkのバージョンは2.2.6で実行しています。
Wiresharkには、主に以下の3つの機能が実装されています。
(1)ネットワークを流れるパケットをキャプチャ する
(2)キャプチャしたパケットを表示する
(3)表示したパケットを解析する
まず、パケット解析をするために、パケット情報をキャプチャしていきます。Wiresharkを起動すると、以下のような画面が表示されます。
ここで、パケット情報を取得したい接続を選択します。すると、以下のようにパケット情報が記録されていきます。
あとは左上2番目の停止ボタンを押下し、ファイルを保存したらパケットのキャプチャは完了です(※sample1.pcapというファイル名で保存)。
ここで保存されたパケットのキャプチャは、WinPcap(Linuxであればlibpcap)ファイルフォーマットというフォーマットで保存されます。このフォーマットはパケットを記録する基本的なフォーマットで、ネットワーク通信を記録するファイルとして、広く使用されています。以下に、そのサンプルを示します。
pcapファイルは、基本的に次の3段構造になっています。
Pcap file header(以下pcapheader)は、pcapファイルそのものの情報を格納する部分です。その最大の特徴は、ファイルの先頭の"D4 C3 B2 A1"という先頭の4バイトです。pcapファイルであれば必ずこのような4バイトから始まっており、pcapファイルを判別する部分になっています。また、pcapheadaerには他にも次のような情報が格納されています。
●pcapファイルフォーマットのバージョン情報
- major version:2バイト "02 00"
- minor version:2バイト "04 00"
●タイムゾーン情報
- timezone:4バイト "00 00 00 00"
●タイムスタンプの精度
- sigfigs:4バイト "00 00 00 00"
●キャプチャできるパケット長の最大長
- snaplen:4バイト "ff ff 00 00"
●データリンク層のヘッダタイプ
- linktype:4バイト "01 00 00 00
pcap headerをまとめると、以下のような構造になっています。
Pcap packet header(以下packet header)は、各パケットに付与されるヘッダで、それぞれのパケットに関する情報が格納されています。具体的には以下の情報が格納されています。
●パケットキャプチャしたときのタイムスタンプ
- 日付を表すUNIXタイムスタンプ:4バイト "72 bb ec 5a"
- マイクロ秒を表すタイムスタンプ:4バイト "82 6a 04 00"
●パケットの長さ
- caplen:4バイト "54 00 00 00"
- len:4バイト "8c 16 45 04"
基本的に、caplenとlenは同じ値ですが、pcap headerのsnaplenよりも大きいパケッ トがパケットキャプチャ中に流れてきた場合、ファイルに記録されるパケット長と実際 のパケット長は異なるので、caplenとlenは異なる値になる可能性があります。
そしてこのpacket headerの後に、各パケットのpacket dataが格納されているという形式になっています。
4.Rubyを使ったパケット解析
pcapファイルの構成がわかった所で、実際の解析に移っていきたいと思います。今回はRubyの拡張ライブラリであるruby-pcapを使用して、解析を行いました。
※Ruby 2.3.1 、ruby-pcap 0.7.9で実行
まず、Rubyの環境下にruby-pcapをインストールします。
$ sudo apt-get install libpcap-dev $ sudo gem install ruby-pcap
次に、例としてIP パケットのsource addressを抽出してくるコードを作成します(先程キャプチャしたsample1.pcapを使用)。
require 'pcap' packets = Pcap::Capture.open_offline('sample1.pcap') packets.each do |packet| puts packet.ip_src if packet.ip? == true end
これを実行すると、以下のように接続していたIPアドレスが羅列されていきます。
172.217.25.232 10.0.2.15 183.79.250.123 104.244.43.112 10.0.2.15 10.0.2.15 104.244.43.112 104.244.43.112 10.0.2.15 104.244.43.112 ... ※以下略
このままだと、無秩序に並んでいるだけなので、タイムスタンプも一緒に出力してIPアドレスごとにソートをかけて出力してみます。
require 'pcap' array = Array.new packets = Pcap::Capture.open_offline('sample1.pcap') packets.each do |packet| ip = packet.ip_src if packetl.ip? == true time = packet.time array.push([ip.to_s,time.to_s,'']) end sorted = array.sort puts sorted
すると、以下のように出力されるようになりました。
54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 54.250.162.79 2018-05-04 05:00:20 +0900 ... ※以下略
実際の解析ではこのように問題となっている接続を特定していきます。
この続きの解析については、次週記事にしたいと思います。
5.おわりに
今回は、パケット解析の前提知識と、基本部分についてお話しました。次回は、実際のCTFの問題などを解いていき、より深い部分に踏み込んで行きたいと思います。次回も興味深い内容になる予定ですので、是非読んでみてください。