脆弱性あった。

風呂に入ってて、ふと気付いた。

#!/usr/bin/perl -w

use strict;
use CGI;

my $cgi = new CGI;

print $cgi->header(-type=>'text/plain', -charset=>'utf-8');
my $datadir = $cgi->param('datadir');
my $mode = $cgi->param('mode');
my $page_name = $cgi->param('page_name');
my $txtdata = $cgi->param('txtdata');

mkdir $datadir if(!(-e $datadir));
chdir $datadir;

if($mode eq 'save' && defined $page_name && defined $txtdata){
	open PAGE, ">$page_name";
	print PAGE $txtdata;
	close PAGE;
	print "saved.";
}
elsif($mode eq 'index'){
	opendir DIR, ".";
	for(readdir DIR){
		print "$_\n" if(-T $_ && $_ ne ".htaccess");
	}
	closedir DIR;
}

訪問者にサーバ開放しちゃうぞー、ってか。

Firebugを使って三分ハッキング。

いっけー、「Run」をクリック。

できました。なんとなく page.html から Firebug でやったけど、そうじゃなくとも
http://konbu.s13.xrea.com/lib/ajax/page4/page.cgi?mode=save&datadir=hoge&page_name=foo&txtdata=hogehoge
とかするだけでも、中身「hogehoge」のテキストを書ける。自明のことながら、例えばサイト全体を「米国政府は宇宙人に牛耳られている」とかいう主張をするサイトに書きかえることだってできる。気をつけましょう。

my $datadir = $cgi->param('datadir');

これはよくないですね。もうこうしちゃいましょう。

my $datadir = "data";

それだけじゃ駄目ですね。

my $page_name = $cgi->param('page_name');

この中身が "../../../../index.html"とかだったら困るんですから。

my $page_name = $cgi->param('page_name');
if(defined $page_name && (index $page_name, "/") >= 0){
	print "Boo.";
	exit;
}

ああ、あと一つ。僕思うわけですが、

print $cgi->header(-type=>'text/plain', -charset=>'utf-8');

より

print "Content-Type: text/plain; charset=utf-8\n\n";

のがわかりやすくないかなって。なので、修正版のpage.cgiは以下のように。

#!/usr/bin/perl -w

use strict;
use CGI;

my $cgi = new CGI;

print "Content-Type: text/plain; charset=utf-8\n\n";

my $datadir = "data";
my $mode = $cgi->param('mode');
my $page_name = $cgi->param('page_name');
if(defined $page_name && (index $page_name, "/") >= 0){
	print "Boo.";
	exit;
}
my $txtdata = $cgi->param('txtdata');

mkdir $datadir if(!(-e $datadir));
chdir $datadir;

if(!defined $mode){
	print "Bye.";
}
elsif($mode eq 'save' && defined $page_name && defined $txtdata){
	open PAGE, ">$page_name";
	print PAGE $txtdata;
	close PAGE;
	print "saved.";
}
elsif($mode eq 'index'){
	opendir DIR, ".";
	for(readdir DIR){
		print "$_\n" if(-T $_ && ($_ ne ".htaccess" and $_ ne ".htpasswd") != 0);
	}
	closedir DIR;
}

データディレクトリの中にphpファイルとか作られて遊ばれても困るね。.htaccessで。

Header set Pragma no-cache
Header set Cache-Control no-cache
SetHandler text/plain

として、全部プレーンテキストとして読まれるように。

他にも問題あるかもしれないけれども。本当、すさまじく間抜け。でもきっと、似たよなことやってる人は世の中けっこう多いんじゃないかなあとも思う。

この日記ページのプログラムはほぼ、 「恥ずかしいソースコードをアップロードしておくことで生産性アップ」*1手法でとりくんでる。でもCGIとかになると、他人に迷惑をかけかねないチキンレースじみたものになってこわいなあと思う。

test