ライトプランではSSHで接続できないのでソースコードから build することができない……ことはないのです。
――そう、CGIならね!
はじめに
さくらが想定した使い方ではないので、すべて自己責任でお願いします。
危険なラッパーを作る
どんなスクリプトでもCGIとして動かせるラッパーを作ります。いうまでもなく危険なので build するときだけ置くようにしましょう。
#!/bin/sh
export USER=`echo -n $DOCUMENT_ROOT | awk -F/ '{print $3}'`
export HOME=/home/$USER
export QUERY_STRING=`echo $QUERY_STRING | awk '/^[[:alnum:]\._-]+$/ {print}'`
IFS=$'\n'
for line in `cat .htaccess`
do
directive=`echo -n $line | awk '{print $1}'`
if [ "$directive" = "SetEnv" ]; then
export `echo -n $line | awk '{print $2"="$3}'`
fi
done
echo "Content-Type: text/plain"
echo ""
exec ./$QUERY_STRING
CGIなのでUSER
やHOME
といった基本的な環境変数もセットされていません。使うことも多いので準備します。
while
の中で .htaccess のSetEnv
ディレクティブを読み込んで環境変数にセットしています。
CGIはsuEXEC
で実行される都合上、環境変数を親プロセスから引き継いでくれないため、.htaccess で SetEnv
しても反映されません。それをここで無理やり反映させています。
危険な .htaccess の配置
標準では .sh
のファイルはCGIとして認識されないので .htaccess で設定します。
<Files "*.sh">
Options +ExecCGI
SetHandler cgi-script
</Files>
上で説明したようにSetEnv
も使えます。
一般的なWebサーバ同様、さくらのレンタルサーバーでも .htaccess はブラウザでアクセスすることはできません。秘密の情報を書くならここに書くのが安全かもしれませんね。
(※SetEnv
では、環境変数と値の区切りはスペースです)
<Files "*.sh">
Options +ExecCGI
SetHandler cgi-script
SetEnv TOP_SECRET I_AM_A_CAT
</Files>
危険な方法で動かすスクリプトの用意
動作させるスクリプトの名前には英数字、アンダースコア(_
)、ハイフン(-
)、ピリオド(.
)しか使えません。引数を与えることもできません。
スクリプト自体はexec
で実行できるものならなんでもOKです。(条件さえそろえばバイナリもいけます)
テストはこんな感じにしました。
#!/bin/sh
env
危険な実行
レンタルサーバーのコントロールパネルから「ファイルマネージャー」を使って危険なラッパーと動作させたいスクリプト、.htaccess をアップロードします。
危険なラッパーがdanger.sh
、スクリプトがbomber.sh
という名前だったら、以下のURLにブラウザでアクセスします。
https://www.example.com/danger.sh?bomber.sh
危険な理由
……わかるな?
(追記: QUERY_STRING
の文字チェックをするようになったので下のは動かなくなりました。よかったよかった)
https://www.example.com/danger.sh?ls
https://www.example.com/danger.sh?yes
危険でもやりたい人向けの注意点
CGIならではの注意点がいくつかあります
-
処理に時間がかかると強制終了(
KILL -9
)させられてしまいます。大きなものを build するのは難しいです。(Python 3.7 を入れようとしたらmake test
で止まった) -
標準エラー出力はサーバのコントロールパネルから「アクセスログの確認」→「エラーログ」で見ることができます。ただし1000行までなので、長くなりそうな場合はリダイレクトしたほうがいいと思います。
-
終わったら消すのを、くれぐれも忘れずに!
危険ついでのおまけ
せっかくなのでPerlでも書いてみました。
#!/usr/bin/perl
if ( $ENV{DOCUMENT_ROOT} =~ m|^(/home/([^/]+))/| ) {
$ENV{HOME} = $1;
$ENV{USER} = $2;
}
my $qs = $ENV{QUERY_STRING} if ( $ENV{QUERY_STRING} =~ m|^[a-zA-Z0-9\._-]+$| );
open(FIN, '<', '.htaccess');
while ( <FIN> ) {
chomp;
s/^\s*//;
my @items = split(/\s+/);
if ( $items[0] eq 'SetEnv' ) {
$ENV{$items[1]} = $items[2];
}
}
close(FIN);
print "Content-Type: text/plain\n\n";
exec("./$qs")
.htaccess のシェルスクリプトとPerlの両対応バージョンは、スマートにFilesMatch
にしました。
<FilesMatch "\.(sh|pl)$">
Options +ExecCGI
SetHandler cgi-script
SetEnv TOP_SECRET I_AM_A_CAT
</FilesMatch>
ここに掲載しているすべてのスクリプトは GitHub にも置いています。
https://github.com/keioni/qiita-sample/tree/master/201908_sakura_lightplan_hack