1. 概要

SSLは、TCP接続を介して暗号化されたデータを交換するための最も一般的なプロトコルです。 また、SSL接続を確立するには、2つのエンドポイントが公開鍵、暗号化アルゴリズム、プロトコルバージョンなどを交換する必要があります。 この交換はSSLハンドシェイクとして知られています。

これは非対称の鍵証明書交換であるため、ハンドシェイクが失敗する可能性があります。 たとえば、サーバーに有効期限が切れた証明書がある場合、またはクライアントとサーバーがSSL / TLSプロトコルバージョンをネゴシエートできない場合、ハンドシェイクは失敗します。

ほとんどの場合、クライアントとサーバー間のSSLハンドシェイクメッセージを分析することで失敗の理由を見つけることができます。このチュートリアルでは、ネットワークを介してこれらのメッセージをキャプチャする方法を学習します。

2. tcpdumpコマンド

tcpdump コマンドを使用すると、Linuxシステムの任意のネットワークインターフェイスでTCPパケットをキャプチャできます。

一般に、通常のSSL交換では多くのTCPトラフィックが流れます。 tcpdumpは非常に便利で、任意の量のデータをキャプチャできますが、これにより、通常、ギガバイトのオーダーの大きなダンプファイルが生成されます。 このようなダンプファイルは、分析できない場合があります。 たとえば、Wiresharkでこのようなダンプを分析するには、多くのリソースが必要になります。

この問題を解決するために、tcpdumpコマンドはいくつかのフィルタリングオプションを提供します。 したがって、フィルタリング条件を満たすTCPパケットのみが出力ダンプにキャプチャされます。

3. SSLハンドシェイクの概要

SSLハンドシェイク中にクライアントとサーバーが交換するメッセージを簡単に見ていきましょう。

  1. Client Hello –クライアントによって発信されました。 これには、プロトコルバージョン、クライアントでサポートされている暗号スイート、および保護されたランダム番号が含まれています。
  2. Server Hello –ClientHelloに応答してサーバーから返されます。 サーバーによって選択されたプロトコルバージョン、クライアントのリストから選択された暗号スイート、暗号化アルゴリズム、およびその他のTLSバージョン固有の拡張機能が含まれます。
  3. サーバー証明書–サーバーによって作成されました。 クライアントが認証する公開証明書チェーンが含まれています。
  4. 証明書要求–サーバーによって発信されました。 このメッセージは、双方向SSLの場合のように、サーバーがクライアントを認証する必要がある場合にのみ送信されます。
  5. Server Hello Done –サーバーによって発信されました。 ServerHelloの終了を示します。
  6. クライアント証明書–クライアント要求に応じてクライアントから返されます。 クライアントは証明書チェーンをサーバーに送信します。
  7. クライアントキー交換–クライアントによって発信されました。 プレマスターシークレットを生成し、サーバーの公開証明書で暗号化します。 次に、マスターシークレットを送信して、暗号化アルゴリズムをサーバーと交換します。
  8. Certificate Verification –サーバーによって発信されました。 これは、クライアントの証明書の認証が成功したことを示します。
  9. Finished –認証とキー交換が成功したことを示すためにクライアントとサーバーの両方から送信されます。

接続の確立中にSSL障害が発生した場合は、上記のメッセージを分析することから始めるとよいでしょう。

これらのメッセージについては詳しく説明しませんが、これらのメッセージはTCPデータパケットの一部であることを理解することが重要です。 したがって、これらのメッセージのみをキャプチャする場合は、前のセクションで学習したものと比較して、高度なフィルタリングオプションが必要です。

これを念頭に置いて、 tcpdump のデータフィルタリングオプションのいくつかを調べ、それらを使用してSSLハンドシェイクメッセージのみをフィルタリングする方法を見てみましょう。

4. tcpdumpでのSSLハンドシェイクメッセージのフィルタリング

ポートホストなどのメタデータに加えて、 tcpdump コマンドはTCPデータのフィルタリングもサポートします。つまり、tcpdumpを使用するとパケット内のデータバイトをフィルター式と照合します。たとえば、特定のTCPフラグを使用してパケットをフィルター処理できます。

tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'

このコマンドは、SYNおよびFINパケットのみをキャプチャし、TCP接続のライフサイクルの分析に役立つ場合があります。

同様に、データバイトの構造がわかっている場合は、SSLハンドシェイクメッセージをフィルタリングできます。 TLS仕様から、ハンドシェイクプロトコルのすべてのメッセージが一意の数値で始まることがわかります。 たとえば、すべてのハンドシェイクメッセージには、最初のデータバイトとして 22、16進数で0x16として表されるが含まれます。

したがって、この事実に基づいて、ハンドシェイクメッセージをフィルタリングする方法を見てみましょう。

4.1. クライアントハローのキャプチャ

クライアントからのSSL接続確立の試行を分析するとします。 このためには、クライアントとサーバー間の ClientHelloメッセージを確認する必要があります。 Client Helloメッセージには、TCPパケットの6番目のデータバイトに01が含まれています。 したがって、そのようなパケットをフィルタリングするには、次のようにします。

tcpdump "tcp port 8081 and (tcp[((tcp[12] & 0xf0) >>2)] = 0x16) \\
  && (tcp[((tcp[12] & 0xf0) >>2)+5] = 0x01)" -w client-hello.pcap

コマンドオプションのさまざまな部分を理解しましょう。

  • tcpポート8081–これがアプリケーションサーバーのSSLポートであると想定して、ポート8081でのみパケットをキャプチャします
  • および(tcp [12]&0xf0) –パケットの13番目のバイトを読み取り、上位4ビットを保持します
  • &&((tcp [12]&0xf0)>> 2) –上記に4を掛けると、TCPヘッダーサイズが得られます

上記のSSLダンプからわかるように、TLSヘッダーはTCPデータパケットの前にあります。 したがって、1番目と6番目のデータバイトを取得するには、TCPヘッダーサイズを計算し、これらのバイトの一致をスキップする必要があります。 上記の2番目と3番目の用語はまさにそれを行います。

これで、tcp[TCPヘッダーサイズ]はパケット内のデータの最初のバイトを指します。 したがって、用語、 tcp [((tcp [12]&0xf0)>> 2)] = 0x16 このバイトが等しいかどうかをチェックします 22、 SSLハンドシェイクの数値コード。 また、tcp [((tcp [12]&0xf0)>> 2)+5] = 0x01は、6番目のバイトが1で、ClientHelloを表すパケットをフィルタリングします。

同様に、前に説明したハンドシェイクメッセージをキャプチャできます。 たとえば、 tcp [((tcp [12]&0xf0)>> 2)+5] = 0x02 為にサーバーこんにちはメッセージ。

4.2. 特定のTLSバージョンでパケットをキャプチャする

SSLプロトコルは時間とともに進化してきました。 SSLv3の後、プロトコルはTLSに引き継がれましたが、これはほとんど同じです。 最近のアプリケーションは通常、TLSv1.3を介してメッセージを交換します。 ただし、多くの場合、下位互換性のためにTLSv1.0、TLSv1.1、およびTLSv1.2が引き続きサポートされています。

TLS仕様では、すべてのTLSバージョンに一意の数値コードが割り当てられています。

  • SSLv3 – 0x300
  • TLSv1.0 – 0x0301
  • TLSv1.1 – 0x0302
  • TLSv1.2 – 0x0303
  • TLSv1.3 – 0x0304

SSLハンドシェイクメッセージでは、データの10バイト目と11バイト目にTLSバージョンが含まれています。したがって、tcpdumpフィルターを適用できます。

tcpdump "tcp port 8081 and (tcp[((tcp[12] & 0xf0) >>2)] = 0x16) \\
  && (tcp[((tcp[12] & 0xf0) >>2)+9] = 0x03) \\
  && (tcp[((tcp[12] & 0xf0) >>2)+10] = 0x03)"

用語 tcp [((tcp [12]&0xf0)>> 2)+9] = 0x03 tcp [((tcp [12]&0xf0)>> 2)+10] = 0x03 10バイト目と11バイト目をチェックして、TLSv1.2を介してすべてのパケットをフィルタリングします。 このコマンドは、TLSv1.2が交換されるすべてのSSLハンドシェイクパケットをキャプチャします。

4.3. TLSを介したアプリケーションデータパケットのキャプチャ

これまでのところ、SSLハンドシェイクメッセージのみをキャプチャしました。 ハンドシェイクが終了すると、クライアントとサーバーはアプリケーションデータを交換できます。 このようなアプリケーションデータパケットには、2番目と3番目のデータバイトにTLSバージョンも含まれています

tcpdump "tcp port 8081 and (tcp[((tcp[12] & 0xf0) >>2)] = 0x17) \\
  && (tcp[((tcp[12] & 0xf0) >>2)+1] = 0x03) \\
  && (tcp[((tcp[12] & 0xf0) >>2)+2] = 0x03)" -w appdata.pcap

ここでは、最初のバイトに 17 があり、2番目と3番目のバイトに03があるパケットをキャプチャするためのフィルターを追加しました。 これは、前に見たように、 17 がアプリケーションデータパケットの数値コードであり、0303がTLSv1.2を示しているためです。

4.4. SSL接続障害のキャプチャ

障害をフィルタリングするために、障害に基づいて15または21を含む最初のバイトをチェックします

tcpdump "tcp port 8081 and (tcp[((tcp[12] & 0xf0) >>2)] = 0x15) || (tcp[((tcp[12] & 0xf0) >>2)] = 0x21)" -w error.pcap

このコマンドは、最初のデータバイトが15または21のいずれかであるパケットをキャプチャします。

5. 結論

この記事では、パケット内のTCPデータを式と照合するためのtcpdumpフィルターについて説明しました。 この知識を使用して、データがフィルター式と一致するパケットを簡単にキャプチャできます。

その後、このアプローチを使用して、メッセージごとに一意の数値コードを照合することにより、SSLハンドシェイクパケットをキャプチャしました。