セキュリティ脆弱性の原因はいろいろ

一口に「セキュリティ脆弱性」と言っても、さまざまなパターンが考えられる。そもそもバグのないソフトウェアや、どんな使い方をしても問題が発生しないソフトウェアというものを探すほうが難しい。どんなソフトウェアでも、(程度の差はあれ)何らかの問題を抱えているものだからだ。

その「何らかの問題」がセキュリティ脆弱性として発動するまでの道のりにはいろいろあるのだが、結局のところ、攻撃者は攻撃するのが簡単で、ついでにroot権限も奪取できるようなバグやセキュリティ脆弱性を好む。root権限を奪ってしまえば、対象となるLinuxシステムの制御権を乗っ取ることができる。そうなれば後はやりたい放題だ。

ほかにもアプリケーションレベルでユーザー認証を回避できるものや、ユーザー名とパスワードがハードコーディングされていてバックドアが開いている状態になっているもの、環境変数に特定の文字列を仕込むと発動するもの、DoS攻撃を受けやすい仕組みになっているもの、特定の手順を踏むとサンドボックスが回避できるものなど、想定される問題は挙げればキリが無い。

ソフトウェアベンダーやプロジェクトチームから発表されるセキュリティ関連のリリースには、どういった原因でどういった問題が存在しているのか、その結果として何が引き起こされる可能性があるのかといった説明が掲載されている。場合によっては、CoPやサンプルコードなども掲載され、すぐにバグを確認できる(バグを利用できる)状況になっているものもある。

C言語を扱えるプログラマーならば、それらの説明文からセキュリティ脆弱性の内容を理解できるだろう。しかし、プログラミングにはあまり縁のないシステム管理者にとっては、少々ハードルが高い。字面から、何か問題があるようだということくらいしかわからないと思う。そこで今回は、そうしたセキュリティ脆弱性でよく登場するものを挙げ、簡単に説明しよう。内容がわかると、少しは親しみ(?)が湧くかもしれない。

バッファオーバーフロー

「バッファオーバーフロー」は、C言語で組まれたプログラムに多い。C言語のプログラムはメモリを確保し、そこにデータを書き込んで利用する。しかし、その部分のコーディングはなかなか面倒なこともあり、プログラマーがちょっと手を抜いたり、「こんな値が書き込まれることはないはずだ」という楽観的な仮定に基づいてコーディングしたりしてしまうケースがある。それがこの脆弱性につながるのだ。

バッファオーバーフローを突く攻撃で多いのは、プログラマーが想定している範囲を超えてデータが書き込まれるケースである。この方法を利用すると、任意のコードを実行させることが可能になる。例えば、/bin/shを起動して、そこにシェルコードを流し込むようなやり方だ。

これはC言語を使い続ける限り、どうしても発生しやすい。コンパイルオプションでバリバリにチェックを入れればある程度回避できるのだが、そうすると、コーディングがちょっと面倒なことになる。そのため、手を抜いた書き方をしたり、コンパイルオプションを無効化したりしてしまうことが多いのだ。

ならばC言語を使わなければ良いではないか、と思うかもしれない。だが、C言語を使うと高速に動作するプログラムを書きやすいし、ライブラリも豊富なので、プログラマーとしては使いたい。LinuxカーネルがC言語で書かれているケースもあり、今後もバッファオーバーフローを利用したセキュリティ脆弱性は出続けるものと考えられる。

デバッグ忘れやハードコーディングによる問題

デバッグ忘れやハードコーディングに起因する問題は、IoT系のデバイスに搭載されるLinuxディストリビューションやソフトウェアによく見られる。一般に、開発時やデバッグ時には、作業を簡略化するために特定のアカウントとパスワードでログインできるようにすることが多いのだが、その設定を削除することなくそのままリリースしてしまうのだ。

それがミスによるものなのか、故意にバックドアとして仕込まれたものなのかの判断はさておき,そういう製品は結構発見されている。それらの製品は、外部からログインできる状況になっているため、やられたい放題だ。

また、アカウント名とパスワードが固定のまま出荷される製品も、同じ問題を抱えたまま運用されることが多い。取扱説明書には最初のセットアップでパスワードを変更するように書いてあるのだが、利用者が変更せず、そのまま使い続けるパターンだ。セキュリティ脆弱性ではなく、利用者の自己責任の範囲という気がしなくもないが(そのあたりは法律の専門家による議論が必要だろう)、実際に多いケースであり、今後も発生することは間違いない。

プロトコル上の問題

インターネットのようなネットワーク環境でソフトウェアが相互に動作するために、プロトコルと呼ばれるやり取りの手順が定められているのだが、このプロトコルに脆弱性となる「穴」のあるケースがある。そして公開されているプロトコルの規約から逆算し、特定の状況下で問題を発動させる方法を見つけ出す攻撃者がいるのだ。

そうした隙を突くような攻撃は、広く使われているプロトコルで行われることが多い。利用者が多いプロトコルのほうが攻撃対象のパイが大きいわけだから、攻撃する側もそういった効率の良いプロトコルを対象にして研究しているわけだ。

迅速にアップデートすることの大切さ

今回紹介したような脆弱性は、挙げていけばキリが無い。2016年のCVEを0001から順に見ていくだけでも「ああ、こんなアプローチもあったか」と感心するほどだ。

現在の社会はコンピュータやソフトウェア無しでは回らない。今後、ソフトウェアの重要性はもっともっと高まるだろう。だとすると、こうしたセキュリティ脆弱性の問題は今後もずっと続くことが考えられる。冒頭でも述べたように、「パーフェクトなソフトウェア」などというものは、ほぼ存在しないからだ。

こうした現状において最も有効な対処方法は、セキュリティ脆弱性が発見され、修正がアップデートされたらすぐに適用する(そして再起動する)ことなのは、間違いない。セキュリティ脆弱性はどうしてもどこかで出てしまうものであり、最良の対策は「できるだけ早く修正すること」というのは、今後も続くだろう。アップデート作業が厄介なのは否めないが、この点についてはあきらめて現実を受け入れ、むしろアップデート作業がすぐ終わるようにルーチン化してしまうのが良いと思う。