サイバーディフェンス研究所 アドベントカレンダー 2022 の 12 日目(8 記事目)です。
クエリされた内容に応じてレスポンスを動的に作って返す、ほろ苦い DNS サーバープログラムを作っていきます。
前菜🥗
なぜそんなものを作りたくなるのかよくわからない。という方向けのちょっと長い解説をします。 想像がつく方はソースコードに進んでください。
DNS は Out-of-band application security testing (OAST) テスト手法の重要なファクターとして利用されています。 OAST はセキュリティテスト対象のホストから外部に向かう通信を誘発させるさせることで脆弱性を検出するテスト手法です。 昨年の今頃大きな騒ぎとなった Apache Log4j 脆弱性のスキャンにも一役買いました。
- Out-of-band application security testing (OAST)
- Out-of-band Application Security Testing with OWASP ZAP
OAST はとりわけ OWASP Top 10 に挙がる程メジャーな脆弱性となった Server-Side Request Forgery (SSRF) と関連が深く、脆弱性の検出や悪用、対策のバイパスに DNS の活用が欠かせません。
当社では OAST 手法のテスト実施のため、プライベートな Burp Collaborator と Interactsh を運用しています(パブリックサーバーのように悪用されないよう気をつけつつ)。
このあたりの話題を掘り下げていくのも一興ですが、話題を自作 DNS サーバーに戻します。 当社では Burp Collaborator と Interactsh のような機能(使用ポート番号)の重複したツールを同居させるなどの目的で、次の機能を持った DNS サーバープログラムを開発・運用しています。
- 権威 DNS サーバー機能
- ゾーンファイルに従ったレスポンスを返す通常の権威 DNS サーバー
- この際の詳細なログが OAST 手法のテストに有用
- 転送機能
- 特定ドメインのクエリを Burp Collaborator と Interactsh へ転送
- 動的なレコード制御
- Let's Encrypt の DNS-01 チャレンジでドメインを検証し、ワイルドカード証明書を発行
- エコー機能
- 今回の内容
だんだん本題に近づいて来ました。
近年メジャー化した SSRF 脆弱性の対策として通信先が内部ネットワークの IP ではないかと検証(フィルター)されることがあります。
このフィルターのバイパスに DNS が一役買うことがあります。
例えば http://127.0.0.1
は内部ネットワークに対する攻撃としてフィルターされてしまうけど、http://localhost.example.com
というペイロードを投げて DNS による名前解決時に localhost.example.com
に対して 127.0.0.1
を返すとフィルターされず内部ネットワークに対して通信できる、といった具合です。
この手の SSRF に関するテクニックは検索するとたくさん出てくるので、興味がわいた方はそちらも研究頂くと楽しいのではないかと思います。
SSRF で通信させたくなる 169.254.169.254
に代表される特別な IP アドレスは調べ始めるといくつもあり、全て調べあげてゾーンファイルに書いておくのはとても面倒だ。。。ということで生まれたのが、今回ご紹介する DNS エコーです。
ソースコード🍝
DNS エコー機能を実装した Go 言語のプログラムです。 コピーして echo.go という名前で保存してください。
コメントに解説を書きながら 99 行に収まってしまうのはひとえに偉大なライブラリーのおかげです 🙏
|
|
いざ、実食🍴
簡単化のため Go module は無効化して実行します(わかる人はよしなにお願いします)。
必要なパッケージを取得します。
$ GO111MODULE=off go get github.com/miekg/dns
実行(ビルド)します。
$ GO111MODULE=off go run echo.go
こういう小さなツールでは、引数をパースする処理をサボりたいし、いちいちプログラムを書き換えるのも面倒ですよね。 実行(ビルド)時に変数を書き換えるという Tips とともに実行します。
$ GO111MODULE=off go run -ldflags '-X "main.domain=echo.example.jp" -X "main.addr=127.0.0.1:8053"' echo.go
プログラムにハードコードされていた情報を書き換えて、IP=127.0.0.1、port=8053、domain=echo.example.jp で待ち受ける DNS エコーサーバーが起動しました。 dig コマンドでいろいろ問い合わせてみます。
# 127.128.129.130 の A レコード
$ dig @127.0.0.1 -p 8053 +short 127.128.129.130.echo.example.jp A
127.128.129.130
$ dig @127.0.0.1 -p 8053 +short 127-128-129-130.echo.example.jp A
127.128.129.130
# ::1 の AAAA レコード
$ dig @127.0.0.1 -p 8053 +short ::1.echo.example.jp AAAA
::1
$ dig @127.0.0.1 -p 8053 +short __1.echo.example.jp AAAA
::1
指定した文字列がそのままレスポンスに返るような動作をしていることがわかります。 サーバー側にはこのようなログが出力されます。
2022/12/xx 16:25:07 [INFO] query: remote=127.0.0.1:32783/udp name=127.128.129.130.echo.example.jp. class=IN type=A data=127.128.129.130
2022/12/xx 16:25:10 [INFO] query: remote=127.0.0.1:57443/udp name=127-128-129-130.echo.example.jp. class=IN type=A data=127.128.129.130
2022/12/xx 16:25:13 [INFO] query: remote=127.0.0.1:49927/udp name=::1.echo.example.jp. class=IN type=AAAA data=::1
2022/12/xx 16:25:16 [INFO] query: remote=127.0.0.1:52142/udp name=__1.echo.example.jp. class=IN type=AAAA data=::1
類似のサービス🍻
今回の記事を書きながら調べていると、DNS Echo と勝手に名付けたこの子と同様の機能を提供するサービスが wildcard DNS service という名前で知られていたらしいことに気づきました。
https://moss.sh/free-wildcard-dns-services/
そうと知らずにアドベントカレンダーに予約したリサーチ不足をなげきました。 しかしよく見てみると既存のサービスは PowerDNS のバックエンドを必要としていたり、ソースコードが公開されているものと見比べると実装言語のパフォーマンスや安全性が期待できたり、なにより 99 行という手軽さです。 むしろ優勝候補?と思ったのでそのまま公開することにしました。
Burp Collaborator や Interactsh もそうですが、我々ペンテスターはセキュリティテストにパブリックなサービスを利用するのは難しいという事情もあります。
ごちそうさまでした🙏
DNS Echo サーバーを簡単に作る方法を紹介しました。 不正利用される可能性もあるので、間違っても重要なドメインで使わないでください。 実用を検討する際はもう少しコネコネしてみてください。
P.S. 写真は昨年クックパッドを見ながら作ったザッハトルテです🍰。今年のクリスマスは何を作ろうか思案中です。