DNS増幅攻撃への参加を防止するか、核コードの作成を経験する

はじめに


この記事では、DNS増幅攻撃をフィルタリングする方法、およびそのアイデアを実装するために書かれた小さなモジュールについて、かなり明白であると思われます。



このようなdns増幅攻撃は、たとえばここに複数回記述されています 。 多くの人がこれに直面し、多くの人が戦い、より成功した人もいれば、そうでない人もいた。 この攻撃は、送信元IPアドレスが被害者のIPアドレスに設定されたDNSサーバーにDNSクエリを送信することに基づいています。 DNSサーバーからの応答は、ほとんどの場合、要求よりも大きくなります。特に、攻撃者は通常、任意の要求を実行することを考慮してください。 AAAAレコーディングはもはや珍しくありません。TXTレコーディングのSPFおよびその他の情報により、5回以上の増幅が非常に簡単になります。 攻撃者にとって、これは非常に魅力的で、大規模なボットネットがなくても、適切な処理を行うことができます。 インターネット上でIPアドレススプーフィングが可能な理由は非常に長い間議論できますが、現実にはそれが可能であるため、今日では、このような攻撃を実行する際に独自のDNSサーバーを使用することを困難にするタスクが非常に重要であるように思われます。 また、この攻撃では、権限のあるDNSサーバーとパブリックリゾルバーの両方を使用できることにも注意してください。 提案されたソリューションは、どちらの場合にも使用できます。



DNSサーバーに適用される主な闘争方法:






実際、アイデアは新しいことをするために思いつきました。 ただし、原則として、DOSに対する理想的な保護手段はなく、提案されたオプションにも欠点がないわけではありません。たとえば、サーバーを使用してdnsトラフィックを増幅せずに反映することは保護されません。 ただし、提案されたソリューションの利点は次のとおりです。



また、iptablesを使用したり、追加のルールを設定したりする必要なく、使用に関してソリューションをできる限りシンプルにしたかったのです。このモジュールはLinux固有ですが、FreeBSDでの実装を根本的に妨げるものはないと思います。



どのように機能しますか?



一定期間内の各IPアドレスから受信したパケットの数を考慮します。 特定のIPから受信したパケットの数がしきい値を超えた場合、TCフラグを使用してUDP応答を形成し、要求を破棄します。 したがって、このトラフィックをDNSサーバーアプリケーションで処理する必要があるために発生するコンテキストスイッチの数を大幅に削減します。 tcフラグ付きのudp応答を受信した正当なクライアントは、TCPを介して要求を繰り返すことを強制され、このトラフィックはすでにDNSサーバーに到達します。



効果的な実装のために、dns要求と応答のヘッダー形式が同じであるという事実は、多くの場合に役立ちます。さらに、dns応答が正しいと見なされるように、ヘッダーはパッケージの唯一の必要な部分です。 dnsヘッダーをさらに詳しく見てみましょう。





別の良いニュース:dnsヘッダーのサイズは12バイトに固定されています。 非常に単純なスキームであることがわかり、dnsヘッダーを完全に解析する必要さえありません。 53 UDPポートに到着したパケットに12バイトを超えるデータが含まれていることを確認し、最初の12バイトのデータをコピーします(書き込み中に、おそらく残りのヘッダーフィールドを追加で確認する必要があるという考えが現れた)リクエストから新しいパケットにTCビットを設定しますそして応答ビット、そしてそれを送り返します。 ヘッダーのみをコピーしたため、QDCOUNTフィールドをリセットすることをお勧めします。リセットしないと、クライアント側でパーサーの警告が表示されます。 その後、リクエスト自体が削除されます。 この作業はすべてNF_INET_LOCAL_INフックで直接行うことができます。同じフックで、さらに統計を計算するためにソースIPをKFIFOキューに入れる必要があります。 着信パケットの統計を、赤黒ツリーを使用して、別のストリームで非同期的に検討します。 したがって、パケットの通過に最小限の遅延を導入します。KFIFOはロックのないデータ構造であり、さらに各CPUにキューが作成されます。 確かに、予想されるppsに応じて間隔を構成する必要があります。 CPUごとのデータに割り当てられるメモリのサイズにはまだ制限があります。現在は、CPUごとに4096個のIPアドレスのキューを考慮して32kBです。 したがって、100msの間隔を選択すると、各CPUに対して最大40960 ppsを計算できます。ほとんどの場合、これで十分と思われます。 一方、キューをオーバーフローさせると、統計用の一部のデータが失われます。



論理的な疑問が生じます。なぜハッシュを使用しないのですか?



残念ながら、そのような場所でハッシュを不正確に使用すると、別のタイプの攻撃の可能性が開かれます-衝突を引き起こすことを目的とした攻撃:実行時に重要なコードの一部でハッシュが使用されていることを知っているため、ハッシュで操作を行うようなデータを取得することができますテーブルは、O(1)ではなくO(n)を超えて既に発生します。 このような攻撃は、それらを特定するのが難しい可能性があるという点でも不快です。明らかに何も起こらず、サーバーが病気になりました。



ブロックされたIPからのppsがしきい値より小さい場合、ブロックは削除されます。 デフォルトでは、しきい値の10%に等しいヒステリシスを設定できます。



記事の最後にプロジェクトへのリンクがあります。 建設的なコメント、提案、追加を歓迎します。



使用例



組み立てられたモジュールがあるディレクトリで、実行します

insmod ./kfdns.ko threshold=100 period=100 hysteresis=10





threshold-tcフラグを設定するしきい値。

period-カウント期間、ms(つまり、この場合、1つのIPから100を超えるパケットが100ミリ秒で受信された場合、フィルターは機能します);

ヒステリシス-応答しきい値とフィルター解放しきい値の差。 ヒント:ヒステリシス=しきい値を設定すると、ロックがトリガーされた後、ロックが解放されることはありません。場合によっては便利です。



モジュールをロードした後

cat /proc/net/kfdns





IPのフィルタリングに該当する統計を見つけることができます。



試験結果





寄生負荷を作成するために、dnsperfが使用されました(2つのインスタンスで、1つは隣接する仮想マシンに、2つ目はラップトップにあり、残念ながらこれはシステムを障害にロードするのに十分ではありませんでした)、dnsサーバーはCentOSを実行するKVM仮想マシンで発生しましたdnsサーバー自体はpdns-recursorによって使用されました。



グラフには、モジュールのアクティブ化前、アクティブ化後、およびモジュールがアンロードされた状態のカウンター値が表示されます。 実験全体のPPSは80kppsのレベルでした。





したがって、私たちが達成したのは、発信トラフィックの削減です。 モジュールをオンにした後、発信トラフィックが着信トラフィックよりも少なくなったことがわかります。

原則として論理的です。タイトルのみをコピーすることを忘れないでください。





コンテキストスイッチの数を急激に減らすことは良いことです。





そして、システムで起こったことは次のとおりです。システム時間の消費の顕著な減少、ユーザー時間は目に見えます。 この場合のスチール時間の変更は仮想化の影響であり、これも論理的です。 しかし、irq時間のわずかな増加は興味深いものであり、さらなる実験の理由かもしれません。



今後何を追加しますか?






プロジェクト自体:

github.com/dcherednik/kfdns4linux



プロジェクトはかなり若い状態ですが、Khabrasocietyに関心のある人々がいて、おそらく誰かに役立つことを願っています。



参考文献と文献:

Linux netfilter Hacking HOWTO

Netfilterモジュールの作成

信頼できないロックガイド

ISBN 978-5-8459-1779-9 Robert Love、The Linux Kernel:開発プロセスの説明



All Articles