Help us understand the problem. What is going on with this article?

glibcの脆弱性対策(取り急ぎiptables/firewalldで叩き落とす!)for CVE-2015-7547

More than 3 years have passed since last update.

はじめに

glibcでヤバメな脆弱性キター!

内容見るに、getaddrinfoの名前朝解決時に悪意あるDNSレスポンスパケット食わされるとexploit発動って…、それほぼ全ての通信を行うアプリが全部ヤバい奴じゃん!!!

てか個人的な話だがタイミングがマジ糞すぎる。昨日深夜から早朝にかけて年に1度の大規模定期メンテナンス弊社オンプレサーバ再起動祭り2016を実施して数100台の物理サーバ再起動を敢行し終わったとこだっつーの!!!!ふッざけんな!まじふざけんな…!

対策(本道)

  • 大抵のディストリビューションではもう脆弱性対応版のglibcが出てるから yum とか apt でガンガン上げる!
  • ただし glibc 上げたら既存プロセスは再起動してやらないといけないのでまぁ全プロセス考えたら一度OSごと再起動するのが早いわね。
    • どうしても再起動したくない場合は最低限外に通信しそうな sshd, nginx, httpd, php-fpm, mysqld, postgresql-server, postfix, dovecot, sendmail, vsftpd, elasticsearch, node, java, docker, etc, etc… あたりは個別に再起動しといたほうがいいかもねっていうかやっぱ全部だからサーバごと再起動するのが早いね!

対策2(邪道、っていうか全台再起動とか大仕事すぎるから少し時間的猶予をくれ!!)

って人は多いと思う。ていうかうちなんてマジそれだしな。あと2日早く言ってくれたらどんなに良かったか…。
DBサーバとかNFSサーバとか参照されてるとこが多すぎる奴とかは大変なので今すぐ再起動とか無理だから少し待って!って人用にとりあえず iptables でぶっ叩けそうなのでその設定を書いておく。

どうやら今回の脆弱性はパケットサイズが2,048バイト以上の場合に成立するらしいので、単純にDNSレスポンスパケットはUDP/TCP共に2048バイト以上のサイズなら捨てるようにしよう!

DNSのパケットで2kbいくようなのなんて普通じゃ殆どありえない(UDPの場合は従来から512バイトって制限あったくらいだしね)からそうそう問題にはならんだろ! まぁDNSSECとかあとDNSサーバ同士のAXFR使ったゾーン転送とかで問題起きるかもだけど。まぁそんくらいか。そういう特殊なとこは適当対策じゃなくてちゃんとやれって話だ!

iptablesの場合

確かパケットサイズでフィルタ出来たような気がするから調べる…。あったあったlengthモジュールだ。↓こんな感じでパケットサイズをレンジ指定で条件付け出来る。

iptablesコマンドで叩き落とす!
sudo iptables -I INPUT -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo iptables -I INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo ip6tables -I INPUT -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo ip6tables -I INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP

パーマネントな設定にしたいなら以下の行を /etc/sysconfig/iptables (ipv6用はip6tables)*filterCOMMIT の間に追加して、

/etc/sysconfig/iptables,ip6tables
-A INPUT -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
-A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
/etc/sysconfig/iptables,ip6tables全体ではこんな感じになってればOK
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
-A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
COMMIT

で、 service iptables restart; service ip6tables restart で反映だ!

firewalldの場合(CentOS7とか)

iptablesとfirewalldは一緒に使えない(というかfirewalldはiptablesの只のラッパーで、今までiptablesを直叩きしてたのをCLIや設定用のI/Fを変えたものなだけ)なので、firewalldでルールを管理してる場合は、その流儀に従って追加をしてやりましょう。

firewall-cmdで叩き落とす!
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP
sudo firewall-cmd --reload

ってことでドーン。

lengthモジュールとか使う場合は普通のadd-ruleのオプションだとできないので --direct オプションでiptablesのオプションをそのまま書いてルール追加。--permanent 付けると設定ファイルへの追加をしただけでこの時点でまだルール自体は効いていないので、firewall-cmd --reload を実行してやることで現在動いてる環境へ反映だ!

ちなみに上記を実行すると /etc/firewalld/direct.xml に以下のようにルールが追加されてるはずだ。

/etc/firewalld/direct.xml
<?xml version="1.0" encoding="utf-8"?>
<direct>
  <rule priority="0" table="filter" ipv="ipv4" chain="INPUT">-p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP</rule>
  <rule priority="0" table="filter" ipv="ipv4" chain="INPUT">-p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP</rule>
  <rule priority="0" table="filter" ipv="ipv6" chain="INPUT">-p udp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP</rule>
  <rule priority="0" table="filter" ipv="ipv6" chain="INPUT">-p tcp --sport 53 -m state --state ESTABLISHED -m length --length 2048: -j DROP</rule>
</direct>

時間稼ぎが出来たらあとは頑張る

スケジュール立てて、いっぱいglibc上げて、いっぱい再起動する。以上!

最終的にはやっぱ頑張るのだ。

追記:懸念事項

ふと思ったんだが、getaddrinfoが処理する層でのDNSのレスポンスサイズって話だと、パケットサイズに制限かけても細かいパケットに分割されてきたのが上の層に来るまでに大きく再構築された場合とかだとすり抜けちゃうかもかな…? まぁ気休め程度と思ってやっぱしちゃんとglibc入れ替える方向は頑張りましょう。これだけやってとりあえず安心して根本放置するのはやめてねーと。

追記:MTUでフラグメント化したら2048バイトのパケットとか来ないんじゃね?って懸念について

MTUでフラグメント化したらパケットは全部2048バイト以下で意味なんじゃね?ッて思ったのでとりあえずstateを足してみた。state有効だとip_conntrackが読み込まれてフラグメント化されたパケットをPREROUTING辺りでデフラグメントしてからINPUTチェーンに来るんだった気がするので、多分filter時点ではMTUの影響は気にしなくて良くなるはず。まぁそこまで詳しく理解してない部分も多いからやっぱり気休めかもしれず。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした