ようこそ、ネットワークセキュリティの世界へ!
みなさん、こんにちは!日夜、インターネットの安全を守るためにパケットと格闘しているネットワークセキュリティスペシャリストです。
突然ですが、みなさんは「DNS(Domain Name System)」と聞いて何を思い浮かべますか?「google.com などのドメイン名を、142.250.196.14 のようなIPアドレスに変換してくれる、インターネットの電話帳のようなもの」と覚えている方が多いのではないでしょうか。
確かにその通りです!DNSはインターネットの超・基本インフラであり、Webサイトを閲覧するときも、メールを送るときも、裏側で必ず働いています。
しかし、この「誰もが日常的に、当たり前のように使っている仕組み」こそが、サイバー攻撃者にとって絶好の「隠れみの」になってしまうことがあります。それが、今回テーマにする「DNSトンネリング」です。
一見すると難しそうなテーマですが、一歩ずつ丁寧に紐解いていけば、決して恐れることはありません。今回は、ネットワークに初めて触れるエンジニアの方に向けて、身近な例え話を交えながら、その仕組みと強力な防御策を優しく解説していきます。準備はいいですか?それでは一緒に学んでいきましょう!
—
1. DNSトンネリングを「郵便配達」で例えてみよう
DNSトンネリングの仕組みを理解するために、まずはインターネットの世界から離れて、私たちの身近な「郵便配達」で考えてみましょう。
ここに、厳しいセキュリティチェックが行われている「とある秘密の研究所」があるとします。
- 研究所のゲートでは、持ち込まれる荷物や手紙の中身が厳しく検査されています。
- しかし、唯一「宛先が書かれたハガキ」だけは、郵便局の配達員が仕分けのために持ち出すことが許可されており、中身を細かく検閲されることなくスルーされています。
ここで、研究所の中に潜入したスパイ(マルウェア)が、外にいるボス(C2サーバー:指令を出すサーバー)に秘密のデータを送りたいと考えました。どうすればセキュリティの目を盗んでデータを送り出せるでしょうか?
スパイはひらめきました。
「ハガキの『宛先住所(ドメイン名)』の欄に、暗号化したデータをこっそり書いて送ればいいんだ!」
【ハガキの宛名面】
宛先: [暗号化された秘密データ].attacker-hq.com 様
1. スパイは、ハガキの宛名に secretdata12345.attacker-hq.com と書きます。
2. このハガキは、正規の郵便配達員(DNSサーバー)に手渡されます。
3. 郵便配達員は、宛先にある attacker-hq.com を管理しているオフィス(攻撃者のサーバー)へ、このハガキを届けます。
4. 攻撃者のオフィスでは、届いたハガキの宛名を見て、「お、secretdata12345 というデータが届いたぞ」と解読します。
郵便配達員は、ただ真面目にハガキを宛先へ届けただけです。しかし結果として、「宛先欄」という本来データを送る場所ではないスペースを使って、情報が外に漏れ出てしまいました。
これが、DNSトンネリングの正体です。
通常の「名前解決(住所の問い合わせ)」という手続きの中に、こっそり別のデータ(トンネル)を潜り込ませるから、このように呼ばれています。
—
2. なぜファイアウォールをすり抜けてしまうのか?
ネットワークの境界には、通常「ファイアウォール(FW)」や「プロキシサーバー」と呼ばれるセキュリティ機器が設置されています。これらは、怪しい通信(Webアクセスや不審なポートへの接続)をブロックする役割を持っています。
しかし、DNSが使用する「ポート53(UDP)」は、ほぼすべてのネットワークで「外への通信が最初から許可」されています。なぜなら、DNSが繋がらないと、社員全員がインターネットのあらゆるWebサイトにアクセスできなくなってしまうからです。
攻撃者はこの「誰もが素通りさせるポート53」に目をつけました。
[社内PC (マルウェア感染)]
│
▼ (DNSクエリ: "dGhlIHNlY3JldCBkYXRhCg==.bad-domain.com" を解決して!)
[社内DNSサーバー] (正規のルートで外へ転送)
│
[ファイアウォール] ─── 「DNSの問い合わせか。よし、通れ!」(スルー)
│
▼
[攻撃者のDNSサーバー (C2サーバー)] ─── 「データをデコードして回収完了!」
このように、ファイアウォールからは「単に社内のPCがどこかのWebサイトのIPアドレスを問い合わせているだけ」に見えるため、何の警告も出さずに通信を通してしまいます。これが、DNSトンネリングが長年、検知の難しい脅威とされてきた理由です。
—
3. ネットワークレベルでの防御策と検知のポイント
では、私たちはこの巧妙な手法に対して、どのように身を守ればよいのでしょうか?
ポイントは、「不自然なハガキの動きを見逃さないこと」です。具体的には、以下の3つのアプローチが有効です。
① DNSクエリログの常時監視と分析
通常のDNSの問い合わせは、google.com や yahoo.co.jp のように短く、人間が読める文字列です。しかし、DNSトンネリングでは、データを詰め込むために「非常に長くてランダムな文字列」になりがちです。
また、大量のデータを小分けにして送るため、「短時間に大量のDNSリクエストが発生する」という特徴もあります。
② DNSクエリの長さ・種類の制限
1つのドメイン名(サブドメインを含む)の最大長さは253文字、1つのラベル(ドットで区切られた部分)は63文字までと決まっています。この限界ギリギリのクエリが頻発していないかを監視します。また、DNSのレコードタイプ(TXT や NULL など、通常あまり頻繁に使われないがデータを多く乗せられるタイプ)の急増に注意します。
③ インテリジェンスを活用したDNSフィルタリング(RPZなど)
新しく取得されたばかりのドメインや、評判(レピュテーション)の悪いドメインへのDNS問い合わせを、DNSサーバーの段階で強制的に遮断(ブロック)します。
—
4. 実践!防御と検知のための具体的なアプローチ
ここからは、インフラエンジニアやセキュリティ担当者が明日から実践できる、具体的な設定や検知の仕組みを見ていきましょう。
防御策A:セキュリティDNS「RPZ(Response Policy Zone)」の設定例
オープンソースのDNSサーバーである BIND9 などでは、RPZという機能を使って、特定の悪意あるドメインへの問い合わせを無効化(ブラックホール化)できます。
以下は、named.conf におけるRPZの簡易設定サンプルです。
// /etc/bind/named.conf.options などの設定ファイル
options {
directory "/var/cache/bind";
// ─── [重要] 信頼できる社内ネットワークからのみクエリを受け付ける ───
allow-query { localhost; 192.168.0.0/16; };
// ─── [重要] 外への名前解決をフォワーダーに任せる場合の設定 ───
forwarders {
1.1.1.3; // マルウェアやフィッシングをブロックするセキュリティDNS (Cloudflare)
9.9.9.9; // 安全なDNS (Quad9)
};
// RPZの有効化設定
response-policy { zone "rpz.blacklist"; };
};
// ブラックリストゾーンの定義
zone "rpz.blacklist" {
type master;
file "/etc/bind/db.rpz.blacklist";
allow-query { none; };
};
そして、/etc/bind/db.rpz.blacklist の中身を以下のように記述します。
$TTL 60
@ IN SOA localhost. root.localhost. (
2026102401 ; シリアル番号
1h ; 定期更新
15m ; 再試行
30d ; 破棄
2h ) ; キャッシュ
IN NS localhost.
; ─── 悪意あるドメイン(C2サーバー等)を検知した際のブロックルール ───
; bad-domain.com へのアクセスを「存在しない(NXDOMAIN)」として返す設定
bad-domain.com IN CNAME .
*.bad-domain.com IN CNAME .
これにより、社内PCが万が一 bad-domain.com に関連するDNSトンネリングを試みても、DNSサーバーが「そんなドメインは存在しません」と嘘の返事(NXDOMAIN)を返すため、通信を不発に終わらせることができます。
—
検知策B:Pythonを使ったDNSログの簡易異常検知スクリプト
次に、DNSサーバーのログから「トンネリングの疑いがある不審なクエリ」をあぶり出す、簡単なPythonスクリプトの例をご紹介します。
このスクリプトは、「サブドメイン部分の長さが異常に長いクエリ」や「エントロピー(文字のランダム度合い)が高いクエリ」を検出します。
import math
import re
# ─── 判定のしきい値設定 ───
# サブドメインの長さがこの値を超えたら警告
LENGTH_THRESHOLD = 30
# 文字のランダム度合い(シャノンエントロピー)のしきい値。高いほどランダム(暗号化データに近い)
ENTROPY_THRESHOLD = 3.5
def calculate_entropy(text):
"""文字列のシャノンエントロピー(ランダム度)を計算する関数"""
if not text:
return 0
entropy = 0
for x in range(256):
p_x = float(text.count(chr(x))) / len(text)
if p_x > 0:
entropy += - p_x * math.log(p_x, 2)
return entropy
def analyze_dns_query(query):
"""DNSクエリを解析して不審な点がないかチェックする関数"""
# ドメイン名からトップドメイン(例: .com)等を除いた「サブドメイン部分」を抽出
parts = query.split('.')
if len(parts) < 3:
return # 解析対象外(通常の短いドメイン)
# 最も左側のサブドメイン(データを埋め込みやすい部分)を取得
subdomain = parts[0]
# 長さのチェック
sub_length = len(subdomain)
# ランダム性のチェック
sub_entropy = calculate_entropy(subdomain)
# ─── 判定ロジック ───
if sub_length > LENGTH_THRESHOLD and sub_entropy > ENTROPY_THRESHOLD:
print(f"[⚠️ 警告] DNSトンネリングの疑いあり!")
print(f" └ クエリ: {query}")
print(f" └ サブドメイン長: {sub_length} 文字 (しきい値: {LENGTH_THRESHOLD})")
print(f" └ ランダム度 (エントロピー): {sub_entropy:.2f} (しきい値: {ENTROPY_THRESHOLD})")
print("-" * 50)
# ─── テスト用の擬似DNSログデータ ───
dns_logs = [
"www.google.com",
"mail.yahoo.co.jp",
# 暗号化した機密データを模した、極端に長くランダムなクエリ
"uYg93HkLa8mQzWp12vNx90bVc.attacker-hq.com",
"api.github.com",
"dXNlcm5hbWU6cGFzc3dvcmQ1Njc4OQ.exfiltration-site.net"
]
print("=== DNSクエリログの解析を開始します ===\n")
for log in dns_logs:
analyze_dns_query(log)
このスクリプトを実行すると、一般的な www.google.com などはスルーされ、ランダムな文字列が埋め込まれた不審なクエリだけが綺麗に検出されるのが分かります。実務では、DNSサーバー(BINDやWindows DNS)が出力するログをSIEM(セキュリティ情報イベント管理システム)やSplunk等に取り込み、これと似たロジックを用いてリアルタイムに監視を行います。
—
5. まとめ:一歩ずつ、より安全なネットワークへ!
今回は、通常許可されているDNSという仕組みを悪用する「DNSトンネリング」について解説しました。
- DNSトンネリングとは: ハガキの「宛先欄」に隠しメッセージを書くように、DNSクエリにデータを忍ばせる手法。
- なぜ見逃されるか: ネットワークの出入り口で、ポート53/UDP(DNS)は基本的に素通りだから。
- どう防ぐか: クエリログを監視し、「長すぎる名前」「不自然なランダム文字列」「大量のアクセス」といった異常な変化に素早く気づくこと。
セキュリティ対策は、一朝一夕で完璧にできるものではありません。しかし、「この通信はなぜ通っているのだろう?」「ここを悪用されたらどうなるだろう?」という、みなさんの日々の素朴な疑問と深い観察眼こそが、最強の盾になります。
これからも、ネットワークの仕組みを楽しく、そして深く学びながら、安全なインフラを一緒に作っていきましょう!
この記事が、みなさんのセキュリティエンジニアとしての第一歩を支えるささやかな力になれば幸いです。また次回の記事でお会いしましょう!
コメント