php memcached クライアントにおける memcached injection について

shibuya perl mongers テクニカルトーク #14 に参加してきました。

そのなかで、 memcached injection というタイトルで発表がありました。

ざっくりと簡単に言えば、
key に改行(CR LF)を含む値が渡された場合、ライブラリの実装によっては、意図しない動作をするよ(= injection される可能性があるよ)!
というもの。

まぁ、詳細については、以下のPDF を見てもらうとして、
http://www.icto.jp/security_report/pdf/sr20080310.pdf

phpmemcached ライブラリはどうなんだろ?

と思って調べてみた。


php で利用可能な memcached ライブラリには、以下の2つがあります。


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