CMD.EXEの罠
はじめに
ありきたりなお話です。これも昔話ぐらいによく知られている話なので、よもや脆弱性と思う人はないでしょう。マイクロソフトWindows(NHK風に言えば「窓」)世界における仕様です。今回は外部プログラム呼び出しです。
プログラムからCMDって使ってますか?
ええ、使ってますよ。そうじゃないとこのコラムの話はじまらないじゃないですか。UNIX系とのマルチプラットフォームでシェルっぽい扱いといえば当然、CMD使うでしょ。
それってマナー違反です!
なんだって!?
いきなり結論になってしまいました。ShellExecute(Ex)とかCreateProcessで実行コマンドに"CMD"なんて書いちゃいけません。そういうことなんですよね。
そうそう、拡張子なしってのがダメなんですよね
何言ってるのですか!
CMDをCMD.EXEにしても、カレントディレクトリの実行ファイルが優先される仕様は変わらないので、ほぼノーガードです。まさに100-1=0です。
じゃ、絶対パスで書くの?C:\Windows\Sytem32\cmd.exeなの?
あなたのWindowsシステム領域のドライブはCですか?Dじゃダメなんですか?*1
正解言えやー
何を信頼すれば安全かって悩む所ですが*2、いとやんごとなきマイクロソフトの啓示によれば、環境変数は信じてよいです。
ということで、WindowsのプログラミングでCMD.EXEを呼び出したい場合、CMD.EXEの絶対パスがセットされている環境変数のCOMSPECを展開して使いましょう。COMSPECを使うのが望ましい実装と思いますが、カレント探すのは仕様なのでバグではありません*3
あるいは面倒ですが、レジストリから探しましょう。といってもこっちの仕様は良く知らない。
当たり前すぎてドキュメントに出てこないですが、カレントディレクトリのバイナリプランティングを阻止するには定石です。
魔法の呪文
いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。
*1:ほとんどダメな気がするが気のせいとしましょう
*2:脆弱じゃないといってるのに!?
*3:ちなみに、PostgreSQLのv12の後に修正が入りましたが、バグでも仕様変更でもないのでバックポートしないって表明がありました。。