【入門編】 TLS/SSLハンドシェークにおけるC2通信のJa3/Ja3sフィンガープリンティング – サイバーセキュリティとプライバシー保護実践ガイド

こんにちは!いつも技術の最前線を追いかけている皆さま、そして「ネットワークってなんだか難しそう…」と一歩踏み出したばかりの初学者の皆さま。ようこそ、私たちの技術メディアへ。

今日は、暗号化という「見えない壁」の向こう側に隠れた、サイバー犯罪者たちの足跡を見つけ出す魔法のような技術、「JA3/JA3sフィンガープリンティング」についてお話しします。

「暗号化されているなら、中身は見られないはずじゃないの?」――そう思ったあなたは、とても鋭い感覚を持っています。その通りです。でも、実は「中身を見なくても、誰が話しているか分かる」方法があるんです。

郵便配達や、秘密の合言葉のやり取りに例えながら、パケットの鼓動を感じるような深い世界へ一緒に飛び込んでみましょう!

—

1. 暗号化という「中身の見えない封筒」の悩み

今のインターネットは、ほとんどが「HTTPS」で暗号化されています。これは私たちのプライバシーを守るための素晴らしい技術ですが、実は悪い人たち(マルウェア)にとっても「自分たちの通信を隠すための隠れみの」になってしまっています。

セキュリティエンジニアは、悪い通信を止めたい。でも、暗号を無理やりこじ開けて中身を確認するのは、プライバシーの観点からも、機械の負荷の点からも、とても大変な作業(SSL/TLS復号)になります。

そこで登場したのが、「封筒の中身を見ずに、封筒の書き方のクセだけで相手を特定する」というアプローチです。

2. TLSハンドシェーク:通信が始まる前の「秘密の挨拶」

通信が始まる前、クライアント(あなたのPCやマルウェア)とサーバーは、「これからどんな暗号で話そうか?」と相談します。これを「TLSハンドシェーク」と呼びます。

この挨拶の流れを、郵便配達で例えてみましょう。

1. Client Hello(クライアントからの挨拶): 「こんにちは!私はこれとこれの暗号が使えます。あと、この拡張機能も持っています!」と書かれたカタログを渡す。
2. Server Hello(サーバーからの返事): 「じゃあ、その中からこの暗号を使いましょう」と決める。

実は、この「カタログの書き方」に、ソフトやOSごとの「強いクセ」が出るんです。

なぜ「クセ」が出るのか?

Google ChromeならChromeなりの、Windows UpdateならWindowsなりのカタログの並び順があります。そして、マルウェアが使う「攻撃用のプログラム」もまた、特定のライブラリ(道具箱)を使っているため、人間とは全く違う、不自然なカタログの書き方をします。

この「カタログの書き方の特徴」を数字の羅列(ハッシュ値)にしたものが、JA3なのです。

3. JA3フィンガープリント:あなたの「握手のクセ」を数値化する

JA3は、Client Hello パケットの中に含まれる特定の5つの項目を、カンマで繋いでギュッと凝縮したものです。

1. TLSのバージョン(例:TLS 1.2)
2. 使える暗号のリスト(暗号スイート)
3. 拡張機能のリスト
4. 楕円曲線の種類
5. 楕円曲線の形式

これらを繋げて、さらに計算(MD5ハッシュ化)すると、例えば e7ed3441589d380c5f958f01f2f8742d というような、そのソフト特有の「指紋(フィンガープリント)」が出来上がります。

JA3sは「サーバー側の指紋」

JA3がクライアント(PC側)なら、JA3sはサーバー側の返事(Server Hello)から作った指紋です。
マルウェアが自分の親玉(C2サーバー)と通信するとき、この「JA3」と「JA3s」の組み合わせは、世界に一つだけの非常に珍しいパターンになります。

4. 実践:JA3をどうやって見分けるのか?

それでは、実際にどのようにこの指紋が見えるのか、Pythonを使ったイメージコードで見てみましょう。本来はネットワークの通り道にある「センサー」で解析しますが、考え方は同じです。

# TLSパケットからJA3を計算するイメージコード(概念的な例です)
import hashlib

def calculate_ja3(tls_fields):
    """
    TLSハンドシェークの5つのフィールドを結合してJA3ハッシュを作成します。
    """
    # 1. バージョン, 2. 暗号スイート, 3. 拡張, 4. 楕円曲線, 5. 曲線形式
    # これらを特定の順番でカンマ区切りにします
    ja3_string = f"{tls_fields['version']},{tls_fields['ciphers']},{tls_fields['extensions']},{tls_fields['curves']},{tls_fields['formats']}"
    
    # MD5という方式でハッシュ化(指紋化)します
    ja3_hash = hashlib.md5(ja3_string.encode()).hexdigest()
    
    return ja3_hash

# 例えば、あるマルウェアが使っているパケット情報
malware_handshake = {
    'version': '771', # TLS 1.2
    'ciphers': '49195-49199-52393', # 特定の暗号の組み合わせ
    'extensions': '0-10-11',
    'curves': '23-24',
    'formats': '0'
}

print(f"この通信の指紋(JA3)は: {calculate_ja3(malware_handshake)} です。")

このように、通信の中身(「銀行に振り込め」とか「データを盗め」といった命令)を見なくても、「この握手の仕方は、あの有名なマルウェア『Emotet』と同じだ!」と瞬時に判断できるわけです。

5. 防御に活かす:IDS/IPSでの設定例

実際の現場では、Suricata(スリカタ)や Zeek(ジーク)といったネットワーク監視ツールを使って、この指紋をリアルタイムでチェックします。

例えば、有名な攻撃ツールの指紋が見つかったら、即座にアラートを上げる設定はこんな風になります。

# Suricata(ネットワーク監視ツール)のルール例
# 特定のJA3ハッシュ(悪いプログラムの指紋)を見つけたら警告を出す設定

alert tls $HOME_NET any -> $EXTERNAL_NET any ( \
    msg:"ATTACK 悪いマルウェアの通信(JA3)を検知しました!"; \
    ja3_hash; \
    content:"e7ed3441589d380c5f958f01f2f8742d"; \
    sid:1000001; rev:1; \
)

この一行があるだけで、暗号化されていて中身が読めないパケットであっても、「あ、これ怪しいやつだ!」とシステムが教えてくれるようになります。まさに「門番が、怪しい変装をした侵入者の『歩き方のクセ』で見破る」ようなイメージですね。

6. まとめ:一歩ずつ、パケットの「声」を聴こう

JA3/JA3sフィンガープリンティングは、暗号化が当たり前になった現代において、私たちのネットワークを守る強力な武器です。

  • 中身を復号しなくていい(プライバシーを守り、処理も軽い)
  • 「道具(ライブラリ)」のクセを見抜く(攻撃者が名前を変えてもバレる)
  • JA3とJA3sを組み合わせるとさらに強力(相手もセットで特定できる)

最初は難しいと感じるかもしれませんが、パケットの一つひとつには、それを作ったプログラマーの意図や、使われている道具の個性が刻まれています。

「この通信、どんな挨拶をしているのかな?」と少しだけ意識してみるだけで、あなたのエンジニアとしての視界はぐっと広がります。これからも、一緒に楽しくネットワークの奥深さを探求していきましょう!

一歩ずつ、着実に。あなたの挑戦を応援しています!

コメント

タイトルとURLをコピーしました