黒塗りの DNS の論文に書いた話のわかりやすい裏付けとして、sibling domain (兄弟ドメイン) の glue キャッシュの上書きを模擬的に実験しました。
以下は実験用のゾーンです。TLD として nom、悪意ある SLD として wine.nom、そして偽 nom を用意します。wine.nom には nom の NS である a.nic.nom を NS に加えておきます。
;172.18.1.1 ;nom zone (before) ; nom. 86000 IN NS a.nic.nom. a.nic.nom. 86400 IN A 172.18.1.1 ; wine.nom. 86400 IN NS ns.wine.nom. wine.nom. 86400 IN NS a.nic.nom. ns.wine.nom. 86400 IN A 172.18.1.2 ;172.18.1.2 ;fake nom zone ; nom. 300 IN NS ns.fake.nom. *.nom. 300 IN A 172.18.1.2
まず、キャッシュサーバ (今回は Unbound 1.10) から wine.nom とは別の beer.nom に関する問い合わせを行っておきます。
root@server_unbound1:/ # dnsqr a www.beer.nom 1 www.beer.nom: 46 bytes, 1+1+0+0 records, response, noerror query: 1 www.beer.nom answer: www.beer.nom 60 A 172.18.1.2
beer.nom を名前解決する過程でキャッシュには root から nom への委譲で得られる a.nic.nom の A レコード 172.18.1.1 が入ります。これは RFC 2181 のキャッシュ優先度ランキングにおいて最下位のキャッシュです。
root@server_unbound1:/ # unbound-control dump_cache START_RRSET_CACHE ;rrset 86388 1 0 1 0 a.nic.nom. 86388 IN A 172.18.1.1 (snip)
次に偽応答を模擬するために nom zone を書き換えます。
;nom zone (after) ; nom. 86000 IN NS a.nic.nom. a.nic.nom. 86400 IN A 172.18.1.2
そして wine.nom の名前解決をキャッシュサーバに要求します。
root@server_unbound1:/ # dnsqr a www.wine.nom 1 www.wine.nom: 46 bytes, 1+1+0+0 records, response, noerror query: 1 www.wine.nom answer: www.wine.nom 10 A 172.18.1.2
このとき nom ゾーンはお節介にも wine.nom への委譲応答に含まれる a.nic.nom について偽の a.nic.nom の A レコードを Additional Section で返します。(本物ですが偽応答と差し替えることができるので模擬的に偽応答と同等と考えられます)
この A レコードは nic.nom のグルーではありますが、wine.nom のグルーではないので、ここで現れるべきものではないのです。(ちなみに実装は NSD を用いています)
root@server_unbound1:/ # dnsq a www.wine.nom 172.18.1.1 1 www.wine.nom: 99 bytes, 1+0+2+2 records, response, noerror query: 1 www.wine.nom authority: wine.nom 86400 NS ns.wine.nom authority: wine.nom 86400 NS a.nic.nom additional: ns.wine.nom 86400 A 172.18.1.2 additional: a.nic.nom 86400 A 172.18.1.2
さてお立ち会い。ここでキャッシュをダンプしてみると、172.18.1.1 だった a.nic.nom のキャッシュが TTL が切れてもいなかったのに上書きされています。
root@server_unbound1:/ # unbound-control dump_cache START_RRSET_CACHE ;rrset 296 1 0 3 0 ns2.wine.nom. 296 IN A 172.18.5.2 ;rrset 86396 1 0 1 0 a.nic.nom. 86396 IN A 172.18.1.2 (snip)
そして念押しで存在しないはずの名前を問い合わせてみると、キャッシュサーバは偽 nom ゾーンに問い合わせてその答えを返してきます。
root@server_unbound1:/ # dnsqr a nonexistent.nom 1 nonexistent.nom: 49 bytes, 1+1+0+0 records, response, noerror query: 1 nonexistent.nom answer: nonexistent.nom 300 A 172.18.1.2
結論: 委譲応答に余計についてくる sibling domain の A レコードを受け入れるキャッシュサーバは危険です。真のグルー以外を受け入れてはいけません。(残念ながらメジャーな実装たちはこの危険な A レコードを受け入れます。)
Copyright by T.Suzuki