「glibcのGHOST脆弱性の内容と検出」はしっかり調べた上で書いていなかったので別エントリとしてまとめておきます。
追記:簡単だったので書かなかったのですが、バリデーション方法がない、とのご意見があったので「ホスト名バリデーションのやり方」を書きました。こちらもどうぞ。
追記:新しいgetaddrinfo問題の方はこちら
攻撃方法
日本語のまとめとしては「GHOST 脆弱性は如何様に使うのか」が良いと思います。詳しくはOpenWall MLのメールが参考になります。
GHOSTでオーバーフローするの4バイトまたは8バイトのようです。基本的なEximの攻撃手順は
- ユーザー入力のホスト部分に不正なIPアドレス形式を用い不正に長い攻撃用データを送る。
- 適切なバリデーション無しで攻撃用の不正なホスト名をgethostbyname()に渡される。
- ヒープオーバーフローでヒープ領域のメモリ管理用の空きサイズを改竄する。
- 空きサイズを改竄した部分にメモリを割当させ、領域に既に割り当てられたメモリ領域にメモリ管理用のデータを書き込ませる。
- メモリ管理情報を含んだ割当済みメモリから情報を読み出す。(503エラーで読み出す)
- もう一度、gethostbyname()を呼び出し既に割当済みのアプリ独自のメモリ管理領域の管理部分のメモリを改竄する。
- 6で改竄したアドレスにSTMPで任意のデータをメモリに書き込む。書き込む内容は5で盗んだメモリ管理情報を元にACLを書き換え、文字列展開機能を使い任意コマンド(コードではない)を実行する。
備考:gethostbynameはホスト名とIPアドレスの区別なく名前(文字列)解決し、hostent構造体を返します。IPアドレスはホスト名より限定的(v4なので15文字)です。普通IPアドレスが入っているハズの文字列であっても、任意の文字列が書き込める場合、IPアドレスを取り扱っているつもりでも影響をうけます。gethostbyname_rはプログラマがバッファを作って渡します。このため、スタック領域のバッファの場合、gethostbynameと異りスタックオーバーフローすることになります。
見事に様々な緩和策を回避して攻撃しています。しかし、今のglibcでは修正済のバグを使ってよくぞここまでやった、と思える攻撃方法です。
ヒープ領域のメモリ割り当て状態の条件も整わなければならないので、攻撃成功確立がどの程度なのか興味があるところです。gethostbynameを使っている点からマルチスレッドアプリケーションではない事が確実なので、結構安定して攻撃可能なのかも知れません。
どんなソフトウェアが危ないのか?
- ユーザー入力のホスト名をバリデーションしないでgethostbyname()を使用している。
- インタラクティブな動作を行っている。(攻撃者からの入力に対してレスポンスがある)
- ソフトウェアが持つ実行機能が利用できる。
同様の攻撃をするには、これらの条件が全てそろう必要があります。この条件を見るとWebアプリの中には適応する物もあるかも知れません。しかし、かなり厳しい条件です。簡単に攻撃できるWebアプリを見つけられるような物ではありません。
大騒ぎになってほとんどのサーバーは対策済みのglibcに更新されていること、攻撃者が態々条件が厳しい攻撃経路を使うとは考えられないこと、攻撃者が使おうとしても攻撃可能な経路を見つけるのは困難であること、を考えるとそこまでリスクが高い脆弱性ではありません。Heartbleedの方が比べ物にならないくらいほどリスクが高いです。
ユーザーにスクリプトだけ実行させているようなサービス、例えば
のようなサイトにとっては脅威です。(メモリレイアウトを操作でき、関数やコマンドの実行ができるような物は危い。例えば、PHPが管理するメモリ領域はデストラクタへのポインタを持っている。とはいってもこの脆弱性で攻撃できるパターンを作るのはかなり難しい。)
どうすれば守れたのか?
Eximはメールサーバーなのでホスト名はネットワーク層からだけでなく、ユーザー入力としても処理しています。ホスト名としてあり得ないデータをアプリでエラーにしていれば攻撃はできませんでした。入力データとしてあり得ないデータをライブラリに直接渡すとリスクが伴います。入力バリデーションを行っていれば問題となりませんでした。
- 入力バリデーションを行い、おかしな入力は拒否する
glibcの脆弱性の有無に関わらず、これだけしていれば任意コマンドの実行という最悪の事態は防げました。
ライブラリのバグ/仕様によるセキュリティ問題
ライブラリのバグ/仕様によるセキュリティ問題は今まで数えきれない程見つかっています。GHOSTの様に攻撃が難しいものばかりではなく、非常に簡単な物も多くあります。「これは自分のアプリの問題ではなく、ライブラリの問題だったから攻撃できても自分の問題ではない」と言っても通用しない可能性があります。ISO 27000/ISMSではソフトウェアに入力バリデーションを行うことを求めています。
開発会社がセキュリティ対策として当たり前にやるべきこと(国際標準規格で求めているセキュリティ対策は当たり前)を実施していないと、瑕疵担保責任を超える損害賠償の対象となるリスクを持つ事になります。
まとめ
大騒ぎして直ぐに対策した方が良い物もありますが、今回のGHOST脆弱性は多くのユーザーにとって慌てて対応する必要性があまりない物でした。脆弱性を発見した方が攻撃手法を解説し、攻撃の難易度が高いことを強調していれば、大騒ぎになるような事はなかったと思います。
あまりこういう事が続くとオオカミ少年(狼と羊飼い)のようになってしまうかも知れません。もしこのような状況になると良くありません。情報公開の方法、情報の利用方法には改善の余地があります。
どうせわかるのですから、攻撃の複雑性、ヒープオーバーフローの概要情報だけでも明確にしていれば状況は変わっていたと思います。
追記:書いた時に不正なREFERERで攻撃用の不正なIPアドレス形式の埋め込まれたURLだとオーバーフローする、と思いながら書いていたら全部IPアドレスと書いていました。gethostbynameがホスト名またはIPアドレスを受け取るのは明らかですが、この部分を修正しました。