特集
» 2015年02月25日 18時00分 公開

31st Chaos Communication Congress:Perlは諸悪の根源か? ヨーロッパで行われた情報セキュリティの祭典「31C3」リポート (2/3)

[中澤上明,@IT]

Perl は使うな!? 脆弱性を誘発し得る言語仕様に迫る

 では、チェック・ポイント・ソフトウエア・テクノロジーズのNetanel Rubin氏によるセッション「The Perl Jam - Exploiting a 20 Year-old Vulnerability」を紹介しましょう。

 Perl(パール)とはプログラミング言語の一つで、現在もエンジニアからの人気が高い言語ですが、プログラミング言語論者からはしばしば「変態的言語」と、その言語仕様をからかうように表現されることがあります。

 プログラミング言語の「あるべき」仕様については非常にたくさんの議論があり、とても紹介できるボリュームではないので割愛しますが、以下では多くの言語に採用されている仕様を「一般的な言語仕様」、そこからかけ離れたPerlの独自仕様を「特殊な言語仕様」と表現します。その上で、この特殊な言語仕様が誘発し得るセキュリティホールを、セッション内容とともに解説していきます。

 まずは、以下のPerlプログラムを見てください。

 Perlにおけるハッシュとは、C++やJavaで言うところのmapに相当するコンテナーオブジェクトです。このソースコードを、Perlは知らないが一般的な言語仕様を知るエンジニアが見ると、以下のような構造を想像するはずです。

 Perl以外の動的型付けの言語を知るエンジニアだけではなく、特に、C++やJavaに代表される静的型付けの言語における型推論の機構をよく知るエンジニアであるほど、「値が型推論された結果、キー『key3』の値はarray(配列を意味する何らかの型)として処理されるであろう」と推測するでしょう。

 ですが、予想を裏切りPerlではそのような結果を返しません。上記のソースコードを実行した後のhash内部のデータ構造は以下のようになります。

 リスト(list)内のデータは要素ごとに分解、展開され、ハッシュ(hash)の要素として追加されるのです。この挙動一つだけ挙げても特殊な言語仕様であることが理解できると思います。この挙動はハッシュの値全体を設定する際に起こるものですが、リストやハッシュの内部構造は他の言語と変わらなくとも、与えられた値の扱い方がかなり特殊な仕様になっている、というわけです。

 このような特殊な一面を持つPerlは、今では少なくなりつつあるものの、長きにわたりWebアプリケーション、いわゆるCGIの開発に使用されてきました。HTTPリクエストの処理に、Perlが用いられている、ということです。

 ここで簡単な例を用いて、実際に存在したPerl言語仕様を悪用した攻撃方法を紹介したいと思います。まずは以下の単純な POST リクエストを見て下さい。

 このHTTPリクエストを受け付けるCGI(セッション変数や上記リクエストのパラメーターをハッシュに格納する単純なプログラム)をPerlで作成したとします。攻撃の結果を分かりやすくするため、例として挙げた「このサイトにログインしている状態であり、セッション変数『userid』にログインユーザーID『itmedia』が設定されている」と仮定して話を進めていきます。

 それではまず、受け付けたPOSTリクエストのパラメーターをパースします。上記リクエスト例では「action」「data」の二つの要素をCGIに送信しています。そして、前述のセッション変数useridと上記リクエストパラメーターを合わせてハッシュに設定します。リクエスト受付後のハッシュの内部データは以下のようになります。

 次にこのリクエストパラメーターを意図的に、以下のように改ざんします。

 dataパラメーターが二つ追加されて、dataパラメーターだけで合計三つ存在します。渡されたこれらのパラメーターは、CGIにて以下のように受け取られます。

 dataパラメーターの追加によって、パラメーターのタイプがリストになり、値もリストとして受け取っています。この改ざん操作に気付くすべがなければ(適切にバリデーションしていなければ)、受け取ったこれらの値は後続の処理によってそのまま検証されず、ハッシュに格納されます。

 ここで、前述のリストのハッシュ展開における仕様を思い出して下さい。一般的な言語仕様と異なり、Perlでは以下のように展開されます。

 リストはハッシュに格納する際に展開される仕様により、リストとして渡された data パラメーターが展開されてしまい、本来のuseridの値(正しい値=itmedia)が、追加したパラメーターの値(data=userid&data=admin)によって更新されてしまいます。

 更新されてしまうのはハッシュの一意制約によるもので、単一のハッシュに同一の名称のキーが存在することを許可していないので、後続の値によって上書かれてしまうためです。

 今回の処理対象となるPOSTリクエストに存在しないuseridの値が、このようにパラメーター操作によって改ざんされてしまう挙動を用いて、「HTTP Parameter Pollution攻撃」と呼ばれるWebアプリケーションへの攻撃に応用することができました。

 万が一このCGIが、ハッシュ上のuseridに対応する権限を取得し、その権限によってサイト全体のアクセスコントロールを行うような設計であった場合、予期せず更新されてしまった値(ここでは結果的にadmin。もしかすると管理者のユーザID)のユーザの権限が取得され、セッションが管理者として動作する「Privilege Escalation(権限昇格)攻撃」を受ける可能性があります。

 この問題は、言語仕様をよく理解しないままアプリケーションを開発してしまうと、思わぬ所に落とし穴があり、想定し得ない箇所がセキュリティホールとなってしまうことを表しています。この挙動を悪用して実際に攻撃に転用できてしまった既知の脆弱性については、下記URLを参照してください。

【関連リンク】

CVE-2014-1572 - User Verification Bypass

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-1572


 これ以外にも、リストを引数へ渡す際の挙動の特殊性や、DBI->quote()にリストを渡した際の挙動を悪用したSQLインジェクション攻撃など、実際に発見された脆弱性を基に解説されていますので、興味のある方は下記の動画を参照してください。

果たして、これはPerlだけの問題か?

 今回紹介したPerlの挙動は、最近追加された仕様ではありません。古くから実装されているものですが、昨年 2014 年になってもまだ多くの脆弱性が報告されているという状況が、興味深いところです。

 このセッションのスピーカーは、「Perl言語は危険で奇怪な言語である。今すぐにPerlを使用するのを止めるべきだ!」というメッセージを発信して締めくくっていますが、私はこの問題はPerlだけに発生する問題ではないと考えています。ほぼ全ての言語に共通することであり、一番大切なポイントは、どんな言語もライブラリも、しっかりマニュアルを読み理解した上で扱わない限り、予期せぬ脆弱性は生み出され続けるのです。このPerlの言語仕様も、いわば特殊な仕様な「だけ」であり、この特殊な仕様をしっかり理解した上で扱えば、場合によっては非常に柔軟で扱いやすい仕様となることもあります。

 脆弱性を監査していると、言語仕様やライブラリ仕様の理解不足により作り込まれたであろう脆弱性を検出する機会が少なくありません。さまざまなアプリケーションで、いまだにたくさんの脆弱性が生み出され続けている現状を打開する第一歩として、開発者ができることは、言語仕様を深く知り、しっかり理解すること。それこそが、脆弱性のないアプリケーションへの近道となると再認識させられるセッションでした。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。