php memcached クライアントにおける memcached injection について
shibuya perl mongers テクニカルトーク #14 に参加してきました。
そのなかで、 memcached injection というタイトルで発表がありました。
ざっくりと簡単に言えば、
key に改行(CR LF)を含む値が渡された場合、ライブラリの実装によっては、意図しない動作をするよ(= injection される可能性があるよ)!
というもの。
まぁ、詳細については、以下のPDF を見てもらうとして、
http://www.icto.jp/security_report/pdf/sr20080310.pdf
と思って調べてみた。
php で利用可能な memcached ライブラリには、以下の2つがあります。
- memcache
- memcached
memcached は後発のライブラリで、 libmemcached のラッパーとなっています。
機能面でも、セッションハンドラとして利用できたり、cas をサポートしていたりと、memcached の方に軍配が上がるのですが、
memcache では injectionへの対応がされているのに対し、
memcached では、injection される可能性があります。
ソースコードをざっと読んでみたのですが、
前述の通り、memcached は libmemcached のラッパーとなっています。
なので、php 側から渡されたキーをそのまま libmemcached の関数へと渡しています。
php_memc_store_impl 関数(php_memcached.c@1060)がストア処理の実態なのですが、
php 側から渡されたキー (変数 server_key) を、
memcached_set_by_key 関数に直接渡しています。(1140行目あたり)
前出の PDF にもあるとおり、少なくとも現在の libmemcached では key に対する前処理は行ってないようですので、injection の可能性があります。
対して、memcache では、 mmc_prepare_key_ex 関数(2:memcache.c@552/3:memcache_pool.c@1664) で、 key に対して前処理を行っていました。
for (i=0; i<*result_len; i++) { result[i] = ((unsigned char)key[i]) > ' ' ? key[i] : '_'; }
result_len は、キー長。 key が php から渡されたキー文字列で、 result が処理済みのキー。
半角スペース、つまり 0x20 以下の文字コードについてはすべてアンダースコアに変換するという処理になっています。
CR(0x0D) も LF(0x0A) も 0x20 以下なので、アンダースコアに変換されることとなり、 このケースの injection は発生しないことになります。
実際に動かしたわけではないので、もしかしたら見落としている部分があるかも知れませんが、とりあえずそんな発見でした。
検証したソースコードのバーションはそれぞれ以下の通りです。
- memcached var.1.0.2
- memcache var2.2.5 / var.3.0.4