shellshockはPerl/CGIでsystem()にダメージありや無しやbashの脆弱性"shellshock"が非常に話題になっておりますが、これがいろいろと事情が入り組んでおり全容がつかみづらい。いうことでここでは全容を理解するのを早々に放棄して、以下のレガシー環境に絞った狭い話をします。レガシーとは言っても、それなりに鉄板の構成なので対象者は多いのでは無いでしょうか。私は老害なので、Perlしか分からないのです。7PerlのCGIの内部で、system()を使っている。(CGIとして動作させており、mod_perlやPSGI/Plackは使っていない)なお、shellshock自体の解説はここでは行いません。基礎知識:CentOSの/bin/shはじめに、/bin/shとbashの関係について予備知識を知っておく必要があります。Linuxにおいて、/bin/shはbashへのシンボリックリンクとなっています。そのため、CentOSにおいてshとbashは「同じもの」です。bash*ただし、これはあまり単純な話ではありません。実はbashは、「自分がshという名前で起動されたときはshを真似して振る舞う」という仕様を持っています。実際、bashのmanを読んでみると、以下のように書いてあります。shという名前でbashを起動すると、bashは古くからあるshの起動動作をできるだけ真似しようとします。POSIX標準にもできるだけ従おうとします。このモードがきちんと実装されていればあまり悲劇はおきなかった(はず)のですが、残念ながらbashのshモードは、bash特有の機能もバリバリ動いてしまうという困った特徴を持っています。そのため、今回のshellshockの根本原因である環境変数内でのfunction定義も、bashのshモードで動きます。bash特有の機能を使っていることに気付かずに、Shebangが「#!/bin/sh」として書かれたシェルスクリプトが世の中にはたくさんあります。Topicsの解説が大変詳しいので一読をおすすめします。http://gihyo.jp/admin/clip/01/ubuntu-topics/291409/26そしていくつかのスクリプト言語は、OSコマンドを実行する機能の実装に、「直接execする」のではなく「/bin/shを起動してコマンドを実行させる」という形式を取っています。このことから、今回の悲劇は起きました。Perlのsystem()関数はどうなのかというと......これがややこしいので、それを本稿で解説します。Perlのsystem関数とshellshockPerlでは、system関数を利用して外部コマンドを呼び出すことができます。これはshellshockの影響を受けます......が、コードの書き方によって影響を受ける場合と受けない場合があります。以下に詳しく見てみましょう。ものすごく簡単な、次のようなPerlスクリプトを考えます。*");ではこのPerlスクリプトを、straceしながら実行してみましょう。0x1854000....(省略)....```あちゃー。*"を与える形で実行しています。*/]というのはstraceが気を利かせて省略してくれており(省略させたくないときは-vオプションも付けましょう)、この中には環境変数がみつしりと詰まつてゐます。ここにshellshockの例の攻撃文字列が入っていると、見事に注入されたコマンドが実行されてしまうわけです。実はそんなに単純ではありません。次のようなソースはどうでしょう。今度は、「ls」だけを実行します。#!/usr/bin/perlsystem("ls");同じだろって感じなのですが、これをstraceしてみましょう。0x1cee000....(省略)....おおおおお。なんとこの場合は、/bin/lsが直接execveされており、シェルを経由していません。そのためこの場合は、shellshockの影響を受けません。「PerlのCGIでsystem関数を使っている場合、shellshockの影響を受けるケースと受けないケースがある」が正解です。system()の引数とその振る舞いこれは、Perlのsystem関数が、もらった引数を見て「シェルを起動して引数を渡す」か「自分で直接execする」かを判断して分岐するためです。ここでゴチャゴチャ言ってないで、公式のPerlDocを読んでみましょう。他のプラットフォームでは異なります)に渡されます。この方がより効率的です。このようにPerlでは、system()への引数が一つだけのときはそこにシェルのメタ文字があるかをチェックされ、メタ文字がある場合はシェルに解釈させる(丸投げする)ために/bin/shが起動されます。指定された場合、もしくは複数の引数がある場合(つまり、コマンドとそのコマンドライン引数を別々に渡した場合)には、シェルは経由しないのでshellshockされません。みたいに明示的にbashを起動していたら、そりゃー当然影響を受けます。自分のスクリプトが影響あるか無いか知りたいsystem関数の解釈だけが分かればいいわけですから、検証したいコードのsystem関数の部分だけ取り出して、それをstraceしながら実行してみれば/bin/shに渡されるのか直接execするのかはすぐ分かります。この検証は引数の解釈だけを見たいので、system()自体が成功するかしないかは関係ありません。検証したいコードのsystem()部分1行だけを切り出してきて、それを手元で1行のPerlスクリプトにしてstraceを試してみるだけで良いわけです。system()内のコマンドは、失敗して構いません。ある例としては、アスタリスク・パイプ・セミコロンなどを含むと、シェルに渡されてしまいます。本ブログは、職場の先輩より情報を頂いて執筆しました。Iさん、ありがとうございます。以下の徳丸先生のブログに、PHPでのシェル経由ケースが記載されています。私はPHPは(ryhttp://blog.tokumaru.org/2013/12/php_21.htmlPerlでの発動条件について、ntsuji氏より情報をいただきました。ありがとうございます。ShellShockがCGIに及ぼす影響を少し過大評価していたかもその他補足Debian系(Ubuntuなど)は慎重で、デフォルトでは/bin/shをdashという原始的なシェルにしています。これはCentOSとの大きな違いです。そのためDebianでの影響はRedHat系と比べてかなり限定的です。宣伝シェルスクリプトの本を書きました。Qiitaの19日目です。関する罪」の情報公開請求をしました月別アーカイブはてなブログをはじめよう!ozumaさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。