@kazSuenaga 毒盛の話について: Orangeさんにも理解してもらえたので、対策話をしましょう。
否定返答についてくるSOAレコードをご存知かと思います。— DNSはむずかしい (@beyondDNS) March 29, 2016
そのうち記事化します。
それまではリンク先の一連のやり取りをご参照ください。
[2016.04.02. 追記]
上記の一連のやり取りで教わったことをまとめます。
※上記にでてくる「温泉」というのは DNS温泉番外編(2016年春) です。
※自分自身、理解を進めながらの整理なので随時追記・修正があります。
この記事は前野さん1と鈴木さん2 がKaminsky および Müller 流の攻撃手法、およびそれらとその延長線にある一連のものとしてまとめられた 開いたパンドラの箱 - 長年放置されてきた DNS の恐るべき欠陥が明らかに によるキャッシュポイズニング(毒入れ)に対する防御手法として、前野さんが考案した検証方法についての議論からの自分の理解の整理です。
(追記:2016/04/02) 前野さんから https://moin.qmail.jp/DNS/毒盛 を元にしているとの指摘をいただきました。現時点(2016/04/02 )でこの記事で書かれているような検証を実際に行うDNSキャッシュサーバの実装は知られていません。
なお、この攻撃方法の指摘があった co.jp ドメインについては現在、 co.jp に対する txt レコードが設定されています。
その後の前野さんの考察によりこの手法の拡張として、否定応答の AUTHORITY SECTION の SOA 以外にも様々な応答が事前に知ることでゾーンの不存在を類推できる材料となることが分かってきています。
この記事ではそのベースとなる基本部分についての整理を目的としました。
(追記: 2016/04/03)
https://moin.qmail.jp/DNS/毒盛/対策/末永/ として、前野さんからコメントをいただいています。
そちらも併せてごらんください。
目次
前提としている状況
関連する技術的仕様
- DNS名前解決はUDPによる通信を優先的に利用している。
そのため問い合わせ元IPアドレスとポート番号、およびTXIDを詐称することにより容易に応答の詐称ができる。 - スタブリゾルバからある問い合わせを受けたDNSキャッシュサーバは、対応する回答が有効なキャッシュにあればそのキャッシュから、ない場合反復検索によって得た対応する回答をキャッシュしつつその回答をスタブリゾルバに回答する(再帰検索要求があった場合。再帰検索要求がなかった場合は実装によるが有効な回答はない)。
- SOA レコードはそのゾーンの頂点にのみ存在するため、
ゾーンカットされていない親ドメイン名のゾーン内にあるサブドメイン名(つまりゾーンではない)に対するSOAは存在しない。(表現修正:2016/04/02、ゾーンカットという表現がふさわしくないため)
攻撃手法の概略
DNSキャッシュサーバに、存在しないゾーンに対するNSレコードの偽応答(毒:攻撃者が意図したDNSコンテンツサーバ)をキャッシュさせることにより、それより下位のドメイン名に対する名前解決をそのDNSコンテンツサーバに誘導し、攻撃者の意図するサーバへアクセスさせる。
- DNSキャッシュサーバから問い合わせ先のDNSコンテンツサーバに問い合わせた際に、正規の応答より早く偽応答を送り込むことによってDNSキャッシュサーバに偽のキャッシュをすることができる。
- ただし、ポートランダマイズとTXIDにより上記の偽応答を1回の攻撃で成功させることは確率的に困難。
- かつ、1度失敗すると問い合わせた名前がないことを示すネガティブキャッシュをDNSキャッシュサーバが保持するため、同一のレコード名での問い合わせはキャッシュが無効になるまで繰り返せない。
- DNSキャッシュサーバへ毒をキャッシュさせる方法として、ランダムなノード名([random].example.co.jp のような)を問い合わせることによって上記のネガティブキャッシュの影響を受けずに連続的に攻撃をすることができる。
問い合わせに対する正常な応答
DNSキャッシュサーバからDNSコンテンツサーバへの問い合わせの正当な応答のうち、この記事内で関係するものは以下の3つがあります。
例は dig による結果を利用しています。status 、ANSWER SECTION、AUTHORITY SECTIONが注目点です。
- 存在するレコードに対する問い合わせの回答
dig +norec txt co.jp @z.dns.jp
- status: NOERROR
- ANSWER SECTION: 問い合わせられたレコードの情報
- AUTHORITY SECTION: そのゾーンのNS
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.7 <<>> +norec txt co.jp @z.dns.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28768 ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 7, ADDITIONAL: 0 ;; QUESTION SECTION: ;co.jp. IN TXT ;; ANSWER SECTION: co.jp. 86400 IN TXT "co.jp." ;; AUTHORITY SECTION: jp. 86400 IN NS d.dns.jp. jp. 86400 IN NS g.dns.jp. jp. 86400 IN NS f.dns.jp. jp. 86400 IN NS a.dns.jp. jp. 86400 IN NS b.dns.jp. jp. 86400 IN NS e.dns.jp. jp. 86400 IN NS c.dns.jp. ;; Query time: 12 msec ;; SERVER: 203.119.1.10#53(203.119.1.10) ;; WHEN: Sat Apr 2 17:36:15 2016 ;; MSG SIZE rcvd: 158
- 問い合わせられたレコードはないがその名前の別のレコードがある場合の回答
dig +norec a co.jp @z.dns.jp
- status: NOERROR
- ANSWER SECTION: なし(NODATA)
- AUTHORITY SECTION: そのゾーンのSOA ※co.jp ドメインはゾーンではなくjpゾーンに含まれるため、SOA は jp のものが返る。
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.7 <<>> +norec a co.jp @z.dns.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45630 ;; flags: qr aa; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;co.jp. IN A ;; AUTHORITY SECTION: jp. 900 IN SOA z.dns.jp. root.dns.jp. 1459585805 3600 900 1814400 900 ;; Query time: 10 msec ;; SERVER: 203.119.1.10#53(203.119.1.10) ;; WHEN: Sat Apr 2 17:43:18 2016 ;; MSG SIZE rcvd: 70
- 実在しない名前に対する問い合わせの場合の回答
dig +norec a a.jp @z.dns.jp
その名前のどんなレコードもないのでSTATUSは NXDOMAIN、否定応答なのでAUTHORITYはSOA- status: NXDOMAIN
- ANSWER SECTION: なし
- AUTHORITY SECTION: そのゾーンのSOA ※co.jp ドメインはゾーンではなくjpゾーンに含まれるため、SOA は jp
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.7 <<>> +norec a a.jp @z.dns.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 25605 ;; flags: qr aa; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;a.jp. IN A ;; AUTHORITY SECTION: jp. 900 IN SOA z.dns.jp. root.dns.jp. 1459586703 3600 900 1814400 900 ;; Query time: 13 msec ;; SERVER: 203.119.1.10#53(203.119.1.10) ;; WHEN: Sat Apr 2 17:53:05 2016 ;; MSG SIZE rcvd: 69
防御方法について
基本原理
以下のロジックにより、DNSキャッシュサーバがキャッシュされていない偽応答を受け取った際、事前にその偽応答があり得ないことを予知することができ、偽応答を無視することができます。
また、そもそもその偽応答に対応する問い合わせを行わないことができます。
- 「攻撃対象となっているドメイン名がゾーンではない」ことを事前にDNSキャッシュサーバが知っていることによって、そのドメイン名に対するNSレコードを受け入れない(正当な回答と認めない)ことができる。
- 事前に「その名前のゾーンは存在しない」ことを知っておくことにより、そのドメイン名に対する問い合わせが発生した際にNSレコードを返さないことができる。
- SOAレコードは
ゾーンカットされている点(=そのゾーンの頂点)にのみ存在することから、ゾーンが存在する場合SOAレコードは問い合わせたドメイン名に対するものと一致する。 - 問い合わせたドメイン名からSOAレコードで返されたラベル名までの間のサブドメインに対しゾーンが存在しないことを知ることができる。
- ゾーンが存在しないことを知っていることにより、上位のサーバに対する問い合わせを発生させずに問い合わせへの応答ができる。
「ドメイン名がゾーンではない」ことを知る方法
- ドメイン名がゾーンではないことを知るために、あるドメイン名に関するレコードを問い合わせた際にNODATA(上記 「問い合わせに対する正常な応答」 2.)およびNXDOMAIN(同 3.)の際にAUTHORITY SECTIONに返ってくるSOAレコードの利用ができる。
- 例で co.jp を問い合わせている際に jp のSOAが返ってきているということは co.jp ゾーンが存在しないことを意味する。
- 同時に co.jp に対する NSレコードがないことを意味する。
- また 例えば example.co.jp について
dig +norec a example.co.jp @z.dns.jp
とすると jp の SOA が返ってくるが、このことから、example.co.jp ゾーン、および co.jp ゾーンの存在しないことを同時に知ることができる。
(追記: 2016/04/03)
ここでいう example.co.jp ドメインは例示のためのものではなく、実際に z.dns.jp サーバで example.co.jp ドメイン名が管理されているために例として書いています。 - (追記: 2016/04/03)
存在する co.jp から委譲されているドメイン名(例えば yahoo.co.jp )についてNXDOMAINとなるような検索すると yahoo.co.jp に対する SOA が返ってくる。このことからyahoo.co.jpゾーンは存在し、 co.jpドメイン と yahoo.co.jpドメイン の間にゾーンカットがあることがわかる。
「ドメイン名がゾーンではない」ことを知るタイミング
- 想定している攻撃手法は1度で成功する確率は非常に低いため、1度目の問い合わせの時点でSOAレコードが取得されることによりゾーンが存在しないことをDNSキャッシュサーバは
事前にそれ以降の攻撃が成功する前に知ることができる。 - 攻撃に限らず通常の(間違った)問い合わせで発生する応答などからも同様にゾーンが存在しないことを知ることができる。
この防御方法の利点
- 原理が単純であり対応が極めて容易である
- 1度目の攻撃をそのまま防御に利用できる
- 正常な問い合わせや単なる間違いも含めて、正しいゾーン境界をしる機会が非常に多い
- 元々本来受け取っているデータを元にするため新たに通信量が増大するわけではない
-
前野さん(qmail.jpの、というとご存知の方が多いかも)
@beyondDNS
Wiki ↩ -
鈴木さん(tss先生、浸透いうな先生といった方がご存知の方が多いかも)
@tss_ontap_o
開いたパンドラの箱 - 長年放置されてきた DNS の恐るべき欠陥が明らかに
キャッシュポイズニングの開いたパンドラの箱 -1-
キャッシュポイズニングの開いたパンドラの箱 -2- ↩
否定情報のSOAだけでなく、Answerありの通常返答も参考にするといいことが分かった。(delegation返答が返ってこないという意味でのzone cuts 不存在です。ただし、grey 扱い)
肯定返答のAuthority Section中のNSレコードは毒盛だけでなく、zone cuts不在情報としても使えることがわかりました。(もし、ついていれば)
対策が対象にしている毒盛手法についてはtssさんのものではなく、https://moin.qmail.jp/DNS/毒盛 に書いたことを元にしています。
追記しました。
zone cut は zone cuts という書き方をみてもわかるように、DNSでは名詞として使われることが多いので注意してください。(ゾーンカットされているという言い方はその意味で
しない方が)
zone cut はゾーンに分けたときに生じる切断部分を指します。ゾーンのトップの上、
あるいは委譲レコードの上という言い方で分かるでしょうか。
親ゾーンと子ゾーンの境界ということですね。
混乱した表記になっていますね。後ほど整理します。
「攻撃手法の概略」にはおかしい点があるが、論点ではないので、とりあえずのコメントはしない。
防御の方で参照するときには指摘するかも。
「正当な問い合わせの応答」はタイトルの意味が不明だが、内容には問題ない。
NXDomain, NoError (no record) がどういう形をしているかの標準的例があれば十分でしょう。
「問い合わせに対する正常な応答」に改めました。
「防御方法について」に関してはwikiをご覧ください。
https://moin.qmail.jp/DNS/%E6%AF%92%E7%9B%9B/%E5%AF%BE%E7%AD%96/%E6%9C%AB%E6%B0%B8
ありがとうございます。
「DNSSECによる検証は使わないときの話である」ことがあるひとから指摘されました。
あまりに当然のことで、書くまでもないと思っていましたが、どうなんでしょう。
DNSSECによる通信や処理量の増大に比べて、充分に簡単・単純で、処理は実装次第といはいえ通信は全く増えない対策で代替できるなら、そちらの方がいいですね。
かつDNSSECはコンテンツサーバの管理者側の100%の対応を求められますが、この方法であればキャッシュサーバの運用者側(言い方を変えれば利用者側)で自衛できる手法であることが手法として有効と思います。
公開では議論したくない話もありますので、メイルをいただけるとうれしい。
この方式による防御を無効化するには、正規のサーバをDDoSなどで無力化すればいいことに気付きました。水責め攻撃の裏に隠れて毒盛すれば、気づかれにくいということもあります。2年以上前から、実行されている可能性があります。
「偽応答を1回の攻撃で成功させることは確率的に困難」という前提を覆すことになる手段ということですね。
問い合わせているドメイン名よりも上位の権威サーバに対してのDDoSなどでも同様ということになりますね。
上位ほどDNSSECを利用していることを踏まえると、攻撃対象とするドメイン名より上位へのDDoSは攻撃者が狙いそうな手法に思えます。