
シンプルなDNSリバインディングサービス
rbndrは、DNSリバインディング脆弱性に対するソフトウェアのテストを行うための、非常にシンプルで非準拠のネームサーバーです。このサーバーは、ホスト名に指定されたアドレスの中からランダムに1つを選択し、非常に低いTTLで回答として返します。
https://en.wikipedia.org/wiki/DNS_rebinding
DNSリバインディングは、TOCTOU(チェック時刻と使用時刻の不一致)脆弱性の一種です。これは、「プリフライト」チェックを誤ってセキュリティプロパティの変更に使用しているサービスがある場合に利用します。例えば、次のようなAPIを持つ(架空の)ブラウザプラグインを考えてみましょう。
AllowUntrustedAccess("foobar.com");
SendArbitraryRequests("foobar.com");
そして、AllowUntrustedAccess() は単にホストにプリフライトHTTPリクエストを送信します。
GET /CanIDisableSecurity HTTP/1.1
サービスが200を返すと、プラグインはホストページに対してそのホスト名への完全なアクセスを許可します。これはセキュリティ上の脆弱性になる可能性があります。なぜなら、あなたが制御するホストとそうでないホストの間を切り替えるrbndrホスト名を指定できるからです。プラグインは、たとえそのサービスが通常はプリフライトチェックを許可しないとしても、任意のIPアドレス(例:内部サービスやlocalhost)への完全なアクセスを許可する可能性があります。
これは非現実的に聞こえるかもしれませんが、まさにAdobe Flash、Oracle Java、その他多くの製品が過去にこうした動作をしており、今でも多くの製品がそのまま動作しています。
AdobeがFlashでこの問題を解決しようとした方法については、こちらをご覧ください:https://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html
この種の攻撃に対して脆弱なソフトウェアの場合、rbndrは/etc/hostsを修正したり、独自のネームサーバーをセットアップしたりすることなく、簡単にテストできる方法です。ソフトウェアが結果をホスト名とIPアドレスの両方ではなく、ホスト名だけに関連付ける場合、任意のIPアドレスへのアクセスを許可させることができます。
ホスト名の形式は単純に次の通りです。
<base-16でエンコードされたIPv4>.<base-16でエンコードされたIPv4>.rbndr.us
しかし、ドット区切りの4つ組から変換するには、以下のウェブサイトも利用できます。
https://lock.cmpxchg8b.com/rebinder.html
例えば、127.0.0.1 と 192.168.0.1 を切り替えるには、それらをダブルワードとしてエンコードし、次を使用します。
7f000001.c0a80001.rbndr.us
実際にテストしてみましょう。
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 192.168.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 192.168.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 192.168.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 127.0.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 127.0.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 192.168.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 127.0.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 127.0.0.1
$ host 7f000001.c0a80001.rbndr.us
7f000001.c0a80001.rbndr.us has address 192.168.0.1
ご覧の通り、サーバーはランダムにいずれかのアドレスを返します。次のようなことを行うかもしれません(擬似コード)。
// 自分が制御するアドレスに解決され、アクセスが許可されるまでAPIを呼び続ける
while (AllowUntrustedAccesss("7f000001.c0a80001.rbndr.us") != true)
;
// アクセスが許可されたので、再バインディングされるのを待つ
while (ConnectToPort("7f000001.c0a80001.rbndr.us", 123) != true)
;
// これで、localhostがセキュリティ低下に同意していなくても、localhost:123 にアクセスできるようになった。
SomethingEvil();