./up の配下にしかアップロード出来ない様にしたつもりが、その上のディレクトリに.htaccessやらindex.htmやらを設置されて困っています。
ソース:
http://showizh.cool.ne.jp/cgitest/uploader.txt
ログが残る様にしたのですが、攻撃の際のログは記録されていません。(通常のアップに関してはちゃんと記録されます)
どこにセキュリティホールがあるんでしょうか?
サーバはレンタルのtok2proです。
不正拡張子のチェック部分が間違っているように思います。下記のように修正してみてください。
foreach(split(/ /,$ngextentions)){ if($name =~ /\.$_/){ print LOG "!!dangerfile!!\n";exit;} }
setparaとかupfileという名前付けが気に入らない。ちゃんと英語にしてくれ、気持ち悪い
それとログに時刻その他が入ってないのもダメだろ
という諸々は置いといて、このCGI経由でなく置かれているんじゃなかろうか?
ログに時刻 - たしかに。
CGI経由じゃない - そんな気もしますね。
# これはダイジョブですか?
if($ENV{'REQUEST_METHOD'} eq 'POST'){ &upfile; }
else {
&setpara;
# で、
sub setpara{
foreach my $pair (split(/&/ , $ENV{QUERY_STRING})){
chop;
my($sep1 , $sep2) = split(/=/ , $pair , 2);
$form{$sep1} = $sep2;
}
if($form{"createdirname"} ne ""){
mkdir $dir."/".$form{"createdirname"}, 0701;
&reload;
}
# が呼ばれてますが、GETリクエストで
createdirname=../../up2
# など入っていると、そのまま作ってしまいそうなのですが・・・
# また、chopもchompにしておかないと、末尾を削除しちゃわないですか?
# 次に
sub viewfile {
if($dir !~ /^\.\/up/ || $dir =~ /\.\./){ print "このフォルダは表示出来ません
";exit}
# ですが、上の例でいくと、
movetodir=./upupupupup
# で、GETリクエストがくると、そのまま通りそうです
# upfileメソッドも同様ですね
# あとは、
use strict;
# は、必ずつけましょーっていうのと、HTML::TemplateなどでMVCを分けたほうがよいのではないでしょうか?
chop要らないですね。どこかからコピペしてきたのがそのまま残っていたようです。
・ディレクトリが意図しない場所に作られてしまう
・頭に"up"がついているディレクトリであればアップロード・表示可能
ということですね。しかし、迷惑ファイルが置かれる場所は ./up の真上のディレクトリ(頭に"up"はついていない)でした。
HTML:\:Templateというのは始めて知りました。
大変参考になりました。ありがとうございます。
あ、言い忘れました。perlのバージョンは5.0なのでJcode.pmを使っています。
HTTPにはユーザーエージェントが受け取り可能なメディアタイプ・言語・エンコーディングを考慮して
適切なリソース(のバリアント)を返すコンテントネゴシエーションという機能があります。
Apacheでは、このバリアントを実現するのに追加の拡張子を付けたファイルを用意するという方法が取られています。
たとえばtest.htmlの日本語版ならtest.html.ja、
英語版ならtest.html.enというファイルをサーバに置きます。
で、件のアップローダですが、test.phpはアップロードできませんが、test.php.jaならアップロードできるわけです。
tok2proのApacheがコンテントネゴシエーションが有効であれば、test.php.jaはPHPとして実行されてしまいます。
PHPファイルを置ければあとはどうにでもなるので、PHPを使ってhtaccessなどを置いたのだと思われます。
犯人がログを改ざんするなどという気の利いたことをしていなければ、PHPファイルをアップロードした記録が残っているかもしれません。
拡張子が最後に来ると決め付けちゃいけないんですね。
なるほど
これが直接の原否なのかどうかは分かりませんが、件のスクリプトでは拡張子のチェック部分に欠陥があり、チェックをすり抜けることが可能であるように思います。
たとえば以下のようなスクリプトは、一見すると .htaccess で終わるファイルを作らせないように見えます。
my $filename = ".htaccess";
if($filename =~/\.htaccess$/){
die "filename error";
}
open(OUT, "> $filename");
close(OUT);
しかし、
my $filename = ".htaccess\x0.txt";
として実行してみると、チェックを通り抜けて .htaccess というファイルが作成されるはずです。このように、ファイル名の途中に \x0 (NUL) を混入することでチェックをすり抜けることが可能となる場合があります。
なお、過去にはこのような問題が情報処理技術者試験でも出題されたことがあります。
参考: http://bakera.jp/ebi/topic/2519
ファイル名をチェックする際には、ファイル名全体が /^[-A-Za-z0-9]+$/ にマッチするかどうか確認するなどした方が良いと思います。
ありがとうございます。
アンダーバーの後のダラーは文字列の最後という意味で合っていると思うのですが。
不正拡張子は(自分でテストし)ちゃんと検出され、ログに出力されています。