Zabbix ドメイン名ハイジャック(ドメインの乗っ取り)を監視

プログラム
プログラムPHPZabbix
スポンサーリンク

2014年11月5日 国内の「.com」サイトでドメイン名の登録情報が不正に書き換えられ、攻撃者が用意した不正サイトに誘導されるドメインハイジャック(ドメインの乗っ取り)が複数発生しているそうです。

ドメイン名管理者としての対策は、利用しているレジストラやリセラーのログインアカウントを適切に管理し、定期的にDNSサーバの登録情報が正しく設定されているか(改ざんされていないか)確認することが求められています。

そこで、Zabbix でドメイン名ハイジャックされていないことを監視する外部スクリプトを作成してみました。

▽ 登録情報の不正書き換えによるドメイン名ハイジャックに関する注意喚起|JPCERTCC
http://www.jpcert.or.jp/at/2014/at140044.html

ドメイン名ハイジャック監視スクリプトの作成

ドメイン名管理者としては、ドメイン名に対応するIPアドレスの改ざんが最悪の事態ですので、管理しているサイトのドメイン名に対応するIPアドレスを定期的に確認することで、ドメイン名ハイジャックをされていないことを監視します。

・監視スクリプトの作成
sudo vi /usr/lib/zabbix/externalscripts/DomainHijack.php

#!/usr/bin/php
<?php
// ドメイン名の指定
// Zabbixのアイテムキー(第1引数)で指定します
$domain = $argv[1];

// ドメイン名に対応するIPアドレスの指定
// Zabbixのアイテムキー(第2引数)で指定します。複数IPアドレスがある場合は、カンマ「,」区切りで指定
$ipAddr = $argv[2];

// Zabbixのキーでカンマ区切りで複数のIPアドレスを指定した場合は 
// 別の引数として分けられて実行される(by TNKさん) 
if ($argv[3]) { 
    for ($i = 3; $i < count($argv); $i++) { 
        $ipAddr .= ',' . $argv[$i]; 
    } 
}

// ドメイン名に対応するIPアドレス(Aレコード)を取得
$answers = dns_get_record($domain, DNS_A);

// IPアドレスを抽出(複数の場合もある)
for ($i = 0; $i < count($answers); $i++) {
    $ips[] = $answers[$i]['ip'];
}
$ips_sorted = sortIps($ips);
$getIpAddr = ($ips_sorted) ? implode(',', $ips_sorted) : null;

// 比較の前処理
$ipAddr = ($ipAddr) ? explode(',', $ipAddr) : null;
$ipAddr = sortIps($ipAddr);
$ipAddr = ($ipAddr) ? implode(',', $ipAddr) : null;

// 取得したIPアドレスが正しいかを比較 0:NG 1:OK
// ここで表示された値がZabbixデータベースに記録されます
if ($ipAddr === $getIpAddr && $ipAddr && $getIpAddr) {
    echo 1;
} else {
    echo 0;
}

// 複数IPアドレスのソート処理関数
function sortIps($ips)
{
    if ($ips) {
        sort($ips);
        return $ips;
    } 
}

「dns_get_record()」で取得したIPアドレスが複数ある場合もあるため、処理が少しややこしくなっていますが(^^;) 単純にIPアドレスが正しいものかを比較しているのみです。

スクリプトのオーナーを zabbixユーザに変更します。

sudo chown zabbix:zabbix /usr/lib/zabbix/externalscripts/DomainHijack.php

スクリプトオーナー(zabbix)に実行権限を追加します。

sudo chmod 700 /usr/lib/zabbix/externalscripts/DomainHijack.php

動作確認

第1引数に監視するドメイン名、第2引数に対応する正しいIPアドレスを指定します。チェックOKであれば「1」NGの場合は「0」が表示されます。

sudo /usr/lib/zabbix/externalscripts/DomainHijack.php example.com 93.184.216.119
1 ←OK

sudo /usr/lib/zabbix/externalscripts/DomainHijack.php example.com 192.0.2.1
0 ←NG

※「example.com」のIPアドレスは、2014年11月7日時点のものです。もしかしたら変っているかもしれませんのでご自身で管理しているドメイン名で確認することをおすすめします。

この監視スクリプトの問題点

この記事を公開した日に、なんと!JPRS(日本レジストリサービス)@OrangeMorishita 様からアドバイスを頂きました。JPRSは日本に割り当てられたドメイン名「.jp」のレジストリ業務を行っている企業です。最近ではテレビCMで見かけた方も多いかと思います。

このサイトのドメイン「apar.jp」も指定事業者を通じて、JPRSさんのお世話になっています(^^)

頂いた問題点と解決方法です。(Twitterリプライより引用)

この方法だとAのTTL分や「まずレジストリのNSを変え、後でそのNSで指定されるAを変える」パターンだと、検知が遅れそうです。

今回はレジストリの権威DNSサーバーに登録される委任に関するレコード(NS/A/AAAA)が書き換えられることにより起こるので、そこを直接チェックするのがよいかと。

今回の騒動はドメイン名「.com」のレジストリに登録される「ドメイン名.com」の権威DNSサーバーの書き換えによって起こった、ドメイン名ハイジャックだったようです。この記事の監視スクリプトでは最終的にはIPアドレスの改ざんを検知できますが、検知までに時間がかかってしまう場合があります。

また、権威DNSサーバーに直接問い合わせることは「dns_get_record()」ではDNSサーバを指定しての問い合わせができないため、digコマンドなどを使って実装することになりそうです。

監視スクリプトを Zabbixアイテムに設定

ドメイン名ハイジャック監視スクリプトを設置するホストを作成します。[設定]→[ホスト]→[ホストの作成]をクリック
zabbix-dh01

適当なホストを作成します。スクリプトを設置するだけの実態のないホストですのでIPアドレス等はそのままでOKです。
zabbix-dh02

作成したホストの「アイテム」をクリックします。
zabbix-dh03

「アイテムの作成」をクリックします。
zabbix-dh04

下記を設定し「追加」をクリックすれば設定完了です。監視するドメイン名と対応するIPアドレスをキーの設定で DomainHijack.php[<ドメイン名>, <IPアドレス>] の形式で指定します。IPアドレスが複数ある場合はカンマ区切り(例:192.0.2.1,192.0.2.2)で指定してください。
zabbix-dh05

[監視データ]→[概要] を表示して、取得した値が「1」(OK)となっていることを確認します。
zabbix-dh06

Zabbix通知トリガーの作成

万一ドメイン名ハイジャックされてしまった場合のために通知トリガーを作成します。

[設定]→[ホスト] スクリプトを設置しているホストの「トリガー」をクリックします。
zabbix-dh07

「トリガーの作成」をクリックします。
zabbix-dh08

下記を設定し「追加」をクリックすれば設定完了です。
条件式は、{<ホスト名>:DomainHijack.php[<ドメイン名>, <IPアドレス>].last()}=0 の形式で指定します。
zabbix-dh09

また、ドメイン名ハイジャックされた時に備えて、レジストラの連絡先や問い合わせ方法を事前に確認しておくことも JPCERT/CCから喚起されています。

この記事をシェアする
あぱーブログをフォローする
スポンサーリンク
スポンサーリンク
あぱーブログ

コメント

  1. TNK より:

    情報を公開頂きありがとうございました。
    試させて頂いたところ、1点問題と思われる個所がございましたの
    でご連絡させて頂きます。

    複数のIPがある場合に、外部チェックのキーにカンマ区切りで指定
    されるとのことですが、そうすると、ZabbixからDomainHijack.php
    が呼び出される際には別の引数として分けられて実行されます。

    例えば、$argv[2]には、キーで複数指定したIPのうち、1つめしか
    入ってこないで、$argv[3]に2つめのIPが入るというようになりま
    す。

    綺麗ではありませんが、以下のようにargvからそれ以降も取得して
    カンマ区切りでつなぐと、それ以降のロジックをそのままで実行で
    きるのではないでしょうか。

    —–
    $ipAddr = “”;
    for ($i = 2; $i 2) {
    $ipAddr = $ipAddr.”,”;
    }
    $ipAddr = $ipAddr.$argv[$i];
    }
    —–

    実装はもっとスマートな実装があるかと思いますが、ご確認頂けれ
    ばと思います。

    • こちらこそご指摘ありがとうございます。
      Zabbixキーの複数引数もカンマ区切りのことを考慮しておりませんでした、、

      頂いたコードを参考に、スクリプトを修正しました(13〜17行目)

  2. […] やり方としては任意の文字列を名前解決可能なスクリプトを作り、Zabbix上で利用できるようにします。スクリプトはあぱーぶろぐさんの記事「Zabbix ドメイン名ハイジャック(ドメインの乗っ取り)を監視」を参考にさせて貰いました。 […]

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