C2サーバの追跡方法:SSL証明やJARM使用

解析

C2(Command & Control)サーバは、マルウェアに感染した端末を遠隔操作するための指令塔です。 攻撃者はその存在を隠すために HTTPS を多用しますが、SSL/TLS 通信には「指紋」が残ります。 本記事では、JA3/JA3S ハッシュ  JARM フィンガープリント を使った C2 サーバ追跡の仕組みを、初心者でも理解できるように解説します。


🔍 C2サーバとは何か?まず基礎から理解しよう

サイバー攻撃において、攻撃者は標的のコンピュータに侵入した後、そのマシンをリモートから操作し続ける必要があります。 そのために使われるのが C2(Command & Control)サーバ、日本語では「指令・制御サーバ」と呼ばれるインフラです。

感染端末(Bot)は定期的にC2サーバへ接続し、「次に何をすればよいか」という命令を受け取ります。 攻撃者はこのチャネルを通じて、ランサムウェアの実行・データの窃取・横断的侵害(ラテラルムーブメント)などを指示します。

 💡 代表的なC2フレームワーク
Cobalt Strike(2012年〜、ペンテスト用だが悪用多数)
Metasploit Framework(オープンソース、汎用)
Sliver(Go製、近年急増)
Brute Ratel C4(2021年〜、AV回避特化)
Havoc(2022年〜、オープンソース)

攻撃者はC2通信を正規トラフィックに偽装するため、HTTPS(TLS暗号化)を利用するケースが急増しています。 しかし暗号化されていても、TLS ハンドシェイクの段階で「どのクライアント/サーバソフトウェアが通信しているか」を示す痕跡が残ります。 それが本記事の核心である TLS フィンガープリント です。


🔐 TLS フィンガープリントとは?

HTTPS 通信が始まるとき、クライアントとサーバは TLS ハンドシェイク というやり取りを行い、 使用する暗号方式や証明書の情報を交換します。このハンドシェイクのパラメータの組み合わせは、 使用しているライブラリやフレームワークに依存するため、ほぼ一意な「指紋(フィンガープリント)」になります。

人間の指紋と同様に、このデジタル指紋を収集・照合することで、 「このサーバは Cobalt Strike を使っている」 といった識別が可能になります。

パラメータ内容
TLS バージョン1.0 / 1.2 / 1.3 など
Cipher Suites対応する暗号アルゴリズムのリスト
拡張フィールド(Extensions)SNI, ALPN, session ticket など
楕円曲線(Elliptic Curves)P-256, X25519 など
圧縮方式null or Deflate など

TLS Client Hello に含まれる主なパラメータ


🧬 JA3 / JA3S ハッシュ ── クライアント&サーバを「特定」する

JA3 とは

JA3 は 2017年に Salesforce の John Althouse、Jeff Atkinson、Josh Atkins が開発した、 TLS クライアントを識別するためのフィンガープリント手法です(名前の由来は3人のイニシャル)。

仕組みはシンプルです。TLS Client Hello パケットから以下の5つの値を抽出し、カンマ・ハイフンで結合した文字列を MD5 ハッシュ化 します。

  1. SSLVersion(TLS バージョン番号)
  2. Ciphers(暗号スイート番号リスト)
  3. Extensions(拡張番号リスト)
  4. EllipticCurves(楕円曲線番号リスト)
  5. EllipticCurvePointFormats(点形式番号リスト)

 JA3 計算例(Cobalt Strike のデフォルト)
生文字列:771,49192-49191-49172-49171-57-56-51-50-53-47-10-5-255,0-11-10-35-22-23,23-24-25,0
JA3 ハッシュ:72a7c4bb6a5b2f5e15a61b3a23f05e49 

この値は 使用するマルウェアのC2クライアント(Beacon)のコードを変更しない限り変わりません。 脅威インテリジェンスサービスが収集・公開しているJA3データベースと照合することで、 「このIPはCobalt Strikeらしい」という判断が可能になります。

JA3S とは

JA3S は同じチームが開発した、サーバ側のフィンガープリントです。 TLS Server Hello から SSLVersion・Ciphers・Extensions を抽出してMD5化します。 JA3(クライアント)と JA3S(サーバ)をペアで見ることで、 「誰が(どのマルウェアが)どのサーバ(どのC2フレームワーク)に接続しているか」という組み合わせ分析が可能になります。

JA3/JA3S の主要ツール

 ① Zeek(ネットワーク監視) + ja3 プラグイン

# Zeek インストール後、ja3 スクリプトを有効化
zeek -i eth0 /opt/zeek/share/zeek/site/ja3/ja3.zeek

# 出力例(ssl.log の一部)
# ts        id.orig_h      ja3                              ja3s
# 1700000000 192.168.1.10  72a7c4bb6a5b2f5e15a61b3a23f05e49 (blank)

② tshark(Wiresharkのコマンドライン版)でpcapから抽出

# Client Hello の Cipher Suites を一覧表示
tshark -r capture.pcap \
  -Y "tls.handshake.type == 1" \
  -T fields \
  -e ip.src -e tls.handshake.ciphersuite

③ Python ライブラリ ja3(pip install)

pip install pyja3
# pcap ファイルから JA3 ハッシュを一括抽出
python3 -m pyja3 -a capture.pcap

④ Suricata(IDS/IPS)

# suricata.yaml の tls ログに ja3 フィールドが自動記録される
# eve.json 例
{
  "event_type": "tls",
  "tls": {
    "ja3": {"string": "...", "hash": "72a7c4bb6a5b2f5e15a61b3a23f05e49"},
    "ja3s": {"string": "...", "hash": "b4ece4d5f13b3d3b5e7e1e3c4a7a2e1f"}
  }
}

JA3 データベース・脅威インテリジェンス

  • abuse.ch JA3 SSL Blacklist:悪意のあるJA3ハッシュのブラックリスト(無料)
  • Salesforce ja3 GitHub:元祖JA3の実装とリスト
  • VirusTotal:ファイル分析時にJA3情報を表示
  • Shodan:インターネット上のサーバのJA3S情報を検索可能

🎯 JARM ── サーバを「能動的に」識別する

JARMとは何か

JARM(Just Another Reconnaissance Markup)は、2020年11月に Salesforce の研究チームが公開した、 TLS サーバを能動的に識別するためのフィンガープリント技術です。 JA3 がパッシブ(通信を傍受して記録)なのに対し、JARM はアクティブスキャン型です。

JARMは対象サーバに対して 10種類の特殊なTLS Client Hello を送信し、サーバがそれぞれにどう応答するかの パターンをハッシュ化して62文字の JARM フィンガープリントを生成します。 TLS ライブラリやそのバージョン・設定が同じであれば、同じJARMが生成されるため、 Cobalt Strike・Merlin・Covenant などのC2フレームワークを識別できます。

 💡 JARMの62文字とは?
10回のプローブそれぞれの応答から 暗号スイート・ALPN・バージョン などを抽出し、 その組み合わせを SHA-256 でハッシュ化したものです。 前半32文字は応答パターンのシグネチャ、後半30文字はSHA-256ハッシュ由来の一意識別子です。

なぜJARMはC2追跡に有効なのか

多くのC2フレームワークは デフォルト設定のまま運用される ケースが非常に多いです。 実際、Salesforceの調査では、Cobalt Strike サーバの約 70% 以上がデフォルト証明書または デフォルトJARMを持つと報告されています(2020年当時)。

また、同一フレームワークから派生したC2サーバはIPアドレスや証明書が異なっていても 同一のJARMフィンガープリントを持ちます。 これにより「1つのC2を発見 → JARMで同種のC2をインターネット全体から列挙」という インフラマッピングが可能になります。

C2 フレームワーク既知のJARM フィンガープリント(例)
Cobalt Strike 4.x07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1b
Metasploit Framework07d19d1ad21d21d07c42d43d000000aa99ce74e2c6d013c745aa52b5cc042d
Covenant2ad2ad0002ad2ad22c2ad2ad2ad2adce980c6a4a8d57f52d112c599d95b7a8
Sliver3fd3fd15d3fd3fd21c3fd3fd3fd3fd9e5f3fd3fd3fd3fd44e3fd3fd3fd3fd
nginx(正規)27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d

※ フィンガープリントはバージョン・設定によって変化します。参考値です。

JARMの使い方 ── ツールとコマンド

 ① jarm(公式Pythonツール)

# インストール
git clone https://github.com/salesforce/jarm.git
cd jarm
pip3 install -r requirements.txt

# 単一ホストのスキャン
python3 jarm.py example.com

# 出力例
# Host: example.com | Port: 443
# JARM: 27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d

# ポートを指定(C2は443以外も使う)
python3 jarm.py malicious-server.com -p 8443

# 複数ホストをファイルから一括処理
python3 jarm.py -i targets.txt -o results.csv

② nmap + JARM NSE スクリプト

# NSE スクリプトを使ったスキャン
nmap --script=tls-jarm -p 443 192.168.1.0/24

# 出力例
# PORT    STATE SERVICE
# 443/tcp open  https
# | tls-jarm:
# |_  07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1b

③ zgrab2(大規模インターネットスキャン)

# CIDRブロックに対してJARMを取得
echo "203.0.113.0/24" | zgrab2 tls --jarm -o output.json

# jq でCobalt Strike のJARMだけフィルタ
cat output.json | jq 'select(.data.tls.result.jarm == "07d14d...")'

④ Shodan でのJARM検索(オンライン)

// Shodan 検索クエリ例
ssl.jarm:07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1b

// Cobalt Strike デフォルト証明書と組み合わせ
ssl.jarm:"07d14d..." ssl.cert.subject.cn:"Major Cobalt Strike"


🔎 SSL証明書ハッシュによるC2追跡

JARM や JA3 の他に、SSL証明書そのものを使ったC2追跡も非常に有効です。 多くの攻撃者は、C2サーバに自己署名証明書デフォルト証明書を使います。 証明書の各フィールドや証明書全体のSHA-1/SHA-256ハッシュを追跡することで、 インフラを横断的に追跡できます。

証明書フィンガープリントの種類

  • SHA-1 / SHA-256 フィンガープリント:証明書全体をハッシュ化した値。同一証明書ならIPが変わっても同値。
  • Subject / Issuer の特徴CN=localhostO=Internet Widgits Pty Ltd などデフォルト文字列
  • Subject Public Key Info(SPKI)ハッシュ:秘密鍵を使い回しているサーバを追跡
  • 証明書シリアル番号:一意な値でキャンペーン内のサーバを紐付け

証明書ハッシュの取得方法

 ① openssl コマンド(最もシンプル)

# 対象サーバの証明書フィンガープリントを取得
echo | openssl s_client -connect target.com:443 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha256

# 出力例
# SHA256 Fingerprint=A1:B2:C3:D4:...:FF

# 証明書の詳細(Subject, Issuer, SAN など)
echo | openssl s_client -connect target.com:443 2>/dev/null \
  | openssl x509 -noout -text

# SPKI ハッシュ(鍵の追跡に使用)
echo | openssl s_client -connect target.com:443 2>/dev/null \
  | openssl x509 -noout -pubkey \
  | openssl pkey -pubin -outform DER \
  | sha256sum

② Censys / Shodan での証明書ハッシュ検索

// Censys(https://search.censys.io)
// SHA-256 ハッシュで全インターネットを検索
parsed.fingerprint_sha256: "a1b2c3d4e5f6..."

// Shodan
ssl.cert.fingerprint:"a1:b2:c3:..."

// Subject の特徴から追跡
ssl.cert.subject.cn:"Major Cobalt Strike"
ssl.cert.subject.o:"cobaltstrike"

③ Python + cryptography ライブラリ

import ssl, socket, hashlib
from cryptography import x509
from cryptography.hazmat.backends import default_backend

def get_cert_fingerprint(host, port=443):
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    with socket.create_connection((host, port), timeout=5) as sock:
        with ctx.wrap_socket(sock, server_hostname=host) as ssock:
            der = ssock.getpeercert(binary_form=True)
    cert = x509.load_der_x509_certificate(der, default_backend())
    sha256 = hashlib.sha256(der).hexdigest()
    print(f"SHA-256: {sha256}")
    print(f"Subject: {cert.subject}")
    print(f"Issuer:  {cert.issuer}")
    print(f"Serial:  {cert.serial_number}")
    return sha256

get_cert_fingerprint("example.com")

Cobalt Strike デフォルト証明書の特徴

Cobalt Strike のデフォルト証明書(Malleable C2 未設定状態)には以下の特徴があり、 Shodan や Censys で容易に発見できます。

  • CN = Major Cobalt Strike
  • O = cobaltstrike
  • 有効期間:発行日から約 10年
  • 自己署名(Issuer = Subject)
  • SHA-1フィンガープリント:6ece5ece4192683d2d84e25b0ba7e04f9cb7eb7c(旧版)


🔗 実践:複数手法を組み合わせたC2インフラ追跡フロー

実際のインシデントレスポンスや脅威インテリジェンス収集では、 JA3・JARM・証明書ハッシュを組み合わせることで、 1台のC2サーバ発見 → キャンペーン全体のインフラ特定という連鎖が可能です。

  1. パッシブDNS・ファイアウォールログから怪しいIPを発見
    例:社内端末が深夜に不審な IP へ HTTPS 通信を繰り返している
  2. JA3 でクライアント(マルウェア)のフィンガープリントを確認
    tshark や Suricata で JA3 ハッシュを抽出 → 脅威インテリジェンスと照合
  3. JARM でサーバ側のC2フレームワークを特定
    python3 jarm.py 203.0.113.10 を実行 → Cobalt Strike に一致
  4. 証明書ハッシュ・SPKIを取得してShodan/Censysで検索
    同じ証明書または同じ鍵ペアを使う他のIPを発見 → 攻撃インフラを列挙
  5. IOC(侵害指標)としてブロックリストに追加
    発見した全IPをファイアウォール・EDRに展開

 ⚠️ 注意:アクティブスキャンの倫理と法律
JARMのようなアクティブスキャンを自組織管理外のサーバに対して行うことは、 国によっては不正アクセス禁止法等に抵触する可能性があります。 Shodan・Censys などの既存のスキャンデータベースを活用し、 自組織ネットワーク以外への直接スキャンは慎重に行いましょう。


🛡️ 防御側の視点:JARMとJA3を組み込んだセキュリティ監視

攻撃を受ける側(ブルーチーム・SOC)として、これらのフィンガープリントを 日常的なネットワーク監視に組み込むことで、検知精度が大幅に向上します。

  • Suricata / Zeek で全アウトバウンド TLS セッションのJA3を自動記録
  • 既知の悪意あるJA3ハッシュ(abuse.ch等から取得)とのリアルタイム照合
  • 新規IPへの接続でJARMを自動取得し、既知C2フィンガープリントと比較
  • Elastic SIEM / Splunk にJA3フィールドを取り込み、異常なクライアントフィンガープリントのアラート設定

📚 まとめ

SSL/TLS は通信内容を暗号化しますが、そのハンドシェイクの「形」は隠せません。 JA3・JA3S・JARM・証明書ハッシュという4つの観点から、 攻撃者のインフラを暗号化越しに追跡することが可能です。

手法何を識別するか主なツールスキャン種別
JA3TLSクライアント(マルウェア)Zeek, Suricata, pyja3パッシブ
JA3STLSサーバ(C2)Zeek, Suricataパッシブ
JARMTLSサーバのフレームワークjarm.py, nmap, zgrab2アクティブ
証明書ハッシュ同一証明書を使うサーバ群openssl, Shodan, Censys両対応

TLS フィンガープリント手法の比較

初心者の方はまず Suricata を導入して JA3 ログを取り始める ことをお勧めします。 EVE JSON 形式で自動的にJA3ハッシュが記録されるため、追加開発なしに脅威検知に活用できます。 さらに一歩進んで JARM スキャンや Shodan での証明書追跡を組み合わせることで、 攻撃インフラ全体を可視化する「プロ級の」脅威ハンティングが実現できます。

 📖 参考リソース
Salesforce JA3 GitHub
Salesforce JARM GitHub
abuse.ch JA3 SSL Blacklist
Censys Internet Search
Shodan 

コメント