https通信をtcpdumpでキャプチャしてWiresharkする方法

11月 5, 2019AmazonLinux_CentOS,Network

概要

はじめに

  • 今回は、サーバーを通過するhttps通信のパケットをキャプチャして調査を開始するまでの流れを説明します。
  • パケットキャプチャには、メジャーなLinuxのtcpdumpコマンドを使用します。tcpdumpコマンドによって取得したダンプの調査は、WindowsクライアントにインストールしたWiresharkを使用します。

前提条件

  • ネットワーク上で発生したトラブルシューティングの初心者向けにまとめます。
  • AWSのVPC内に設置したリバースプロキシ(EC2)→ ALB → ウェブサーバー構成があり、今回はリバースプロキシにてtcpdumpを取得します。(疎通確認は、踏み台(EC2)からcurlを投げます)
  • EC2は、Amazon Linux 2を使用します。リバースプロキシ(EC2)までの通信はhttps(443)、リバースプロキシ(EC2)~後続のALB間はhttp(80)となります。
  • 事前にWindowsクライアントにWiresharkをインストールします。httpsの暗号を復号化するための秘密鍵を準備します。

 

パケットキャプチャの方法

tcpdumpコマンドによるパケットキャプチャ

  • キャプチャ対象のサーバーに、tcpdumpを仕掛けます。
    • tcpdumpをスーパーユーザーで実行します。
    • 複数のインタフェースがあれば、-i でインタフェースを指定します。今回は1つしかないため、省略します。
    • -s でキャプチャするサイズを指定します。デフォルトはサイズの制限があるとのことで、-s 0 を指定します。
    • ポートの絞り込みが可能であれば、port XX(送受信のポート指定)or src port XX(受信のポート指定)or dst port XX(送信のポート指定) を指定します。今回は送受信のポートを 443 に指定します。
    • -w でダンプファイルを指定します。長期間取得する場合は、書き込むファイルシステムの空き容量を確認しましょう。

$ sudo tcpdump -s 0 -w /tmp/tcpdump_20191022-1.out port 443
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C61 packets captured ← リクエスト終了後に、[Ctrl]+[C]にて停止
61 packets received by filter
0 packets dropped by kernel
  • テスト用のサーバーからリクエスト(curlコマンド)を投げます。

$ curl -v --resolve dev01.example.com:443:10.10.1.23 https://dev01.example.com/healthCheck --cacert XXXXX.pem.cer
** 省略 **
< HTTP/1.1 200 OK
< Date: Tue, 22 Oct 2019 05:13:47 GMT
< Server: Apache
< Content-Type: application/json;charset=UTF-8
< Content-Length: 19
<
* Connection #0 to host dev01.example.com left intact
Received a request.
  • tcpdumpの採取が長時間の場合、ログアウトしてもプロセスが停止しないようにnohupを付けて実行します。プロセスを停止させる場合は、killコマンド or pkillコマンドを使用します。

$ nohup sudo tcpdump -s 0 -w /tmp/tcpdump_20191022-1.out port 443 &

tcpdumpをcronで実行するなら

  • tcpdumpをcronを使って定期実行する場合は、注意が必要です。シェルスクリプトを実行したプロセスが停止してもtcpdumpは停止しません(おそらくパケットキャプチャの書き込みも中途半端な結果になると思われます)。
  • 下記オプションを指定して、ログローテーションの間隔/秒(-G60), ローテーションの回数(-W1)を指定することで、結果としてローテーション後にtcpdumpコマンドが停止します。
  • ファイル名が重複しないようにdateコマンドを付加しています。(例:tcpdump_202001070939.out)

sudo tcpdump -s 0 -w /tmp/tcpdump_`date '+%Y%m%d%H%M'`.out -W1 -G60 &
sleep 60
exit

 

scp or sftpによるダンプファイルのダウンロード

  • scp or sftpコマンドあるいはCyberduckなどのソフトウェアを使用して、Wiresharkをインストールしたクライアントにダンプファイルをダウンロードします。

 

Wiresharkによるダンプ調査

SSLで暗号化された通信の復号化

  • Wiresharkを起動し、ダンプファイルを開きます。
  • SSLによって暗号化された通信は、「Application Data」として表示されています。以下画像のNo.25-26 のパケットは「Application Data」であり、TLS 1.2で暗号化されたパケットであることが分かります。
  • 右クリックして、「プロトコル設定」→「Open Transport Layer Security preferences…」をクリックします。

 

  • 下記画面にて、「RSA keys list」の「Edit」を押します。

 

  • 復号化の対象となるサーバーのIPアドレス、Port を入力し、Key Fileに復号化の対象となるサーバーで使用する秘密鍵を指定します。

 

  • TLSに秘密鍵を登録後、先の画像に記した「Disable TLS…」を選択します。
  • 先ほどのNo.25-26 のパケットが「Application Data」から実際のデータに変わり、パケットが復号化されたことを確認します。

 

Timeからパケットを絞り込む

  • デフォルトでは、Timeが「キャプチャ開始からの秒数」になっているため、時刻表示形式を通常の「日時」に変更します。特定のTimeのみにパケットを絞り込む際に有効です。
  • メニューの「表示」→「時刻表示形式」から、下記の様に日時に変更します。

 

フィルタの使い方

  • Wiresharkでは、メニューの下に位置するテキストボックスに条件を入力することで、条件に一致したパケットのみを表示させるDisplay Filtersが使用可能です。テキストボックスの左隣にあるアイコンを押し、一覧から条件の候補を選択して、Display Filtersの構文を利用することもできます。
  • 例えば、「ip.addr == xxx.xxx.xxx.xxx」と入力してIPアドレスによるフィルター、「tcp.port == XXX」と入力してPortによるフィルターが可能です。

 

特定のTCPコネクションを抽出

  • tcpdumpで取得したダンプファイルには多くのコネクションに関するパケットが記録されており、上から順に読むには時間が掛かります。先ずは特定のTCPコネクションを抽出して、一連のコネクションのみにフォーカスした調査が有効です。
  • 特定のTCPコネクションを抽出するには、送信元のTCP Port番号(tcp.port)を指定します。一般的にPort番号は1~1023はウェルノウンポートとして定められていますが、1024から65535まではエフェメラルポートと言い、クライアントがサーバー(例:httpsの443)と接続している間だけ一時的に割り当てられるポートです(通信セッション終了後、ポートは再び利用可能な状態になります)。前述のDisplay Filtersに、このクライアントからのエフェメラルポートを指定することで、特定のコネクションに的を絞り、調査を行います。
  • 下記の例は、送信元、送信先のIPアドレス、およびエフェメラルポート(例:39836)を AND条件で指定してフィルタしています。
    • Display Filtersに「ip.addr == xxx.xxx.xxx.xxx && tcp.port == XXX」の条件を指定して、特定のコネクションのみ表示
    • また、左端のラインからも同一のコネクションを判別可。

   

参考資料

パケット解析の流れ

  • パケット解析の流れは、きよぽんさんの「ネットワーク入門のサイト」にまとめられている「Wiresharkを使った解析」の記事が参考になります。また、「Wiresharkの使い方」にインストールから基本的な使い方もまとまっています。参照ください。

SSLハンドシェイクの読み方

  • SSHハンドシェイクの読み方は、下記Qiita の記事が参考になります。

 

  • これで今日からネットワークのトラブルシューティングも恐れることはありません!