TOWN(CGIゲーム)の脆弱性の案内2件

JVN (https://jvn.jp/)

VN: JVN#12513975 クロスサイトスクリプティング

https://jvn.jp/jp/JVN12513975/

VN: JVN#41703192 ディレクトリトラバーサル

https://jvn.jp/jp/JVN41703192/

2013年11月01日作成
2013年11月21日再編集

この度、使い方によって、任意のコードが実行できる脆弱性がtownにて報告され、確認されました。

これは、town の始めから現在(改造版 TOWN 5_10)に至るまでの継承性のあるバグと思われます。

town のプログラムによる発生で、他のゲームなどとは関係ない独自のミスによることが想定されます。

関係各位様は、管理人に連絡して、脆弱性の解消をお願いします。

追記

遠隔の第三者によって、サーバ上の任意のファイルを取得される可能性があります。
つまり、管理者のパスワード等が見られて、偽管理人になりすまし好き放題出来ると言う事です。

クロスサイトスクリプティングは、この色
ディレクトリトラバーサルは、この色
状況に応じては、この色
削除可能は、この色
Tab はタブの代わり入れてあります。
添付ファイル参照の事。

変更箇所 town_lib.pl 最低限

######################
# cgi_lib.pl 使用の方
######################

#デコード処理
sub decode {
Tab local($buf, $key, $val, @buf,$get_in); #koko2013/10/31
Tab if ($ENV{'REQUEST_METHOD'} eq "POST") {
Tab Tab &ReadParse;
Tab Tab while (($key,$value)=each %in){
Tab Tab Tab if ($key ne "upfile"){
Tab Tab Tab Tab &jcode'convert(*value,"sjis");
Tab Tab Tab Tab # $value =~ s/,/,/g;
Tab Tab Tab Tab $value =~ s/\r\n/<br>/g;
Tab Tab Tab Tab $value =~ s/\r/<br>/g;
Tab Tab Tab Tab $value =~ s/\n/<br>/g;
Tab Tab Tab }
Tab Tab Tab $value =~ s/\0/0/g; #koko2013/11/10
Tab Tab Tab $value =~ s/\.\.\//..//g; #koko2013/11/10 ../を../とする。
Tab Tab Tab $in{$key} = $value;
Tab Tab }
Tab } else { $buf = $ENV{'QUERY_STRING'};$get_in = 1; } #koko2013/10/31
Tab @buf = split(/&/, $buf);
Tab foreach (@buf) {
Tab Tab ($key, $val) = split(/=/);
Tab Tab $val =~ tr/+/ /;
Tab Tab $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
#koko2013/10/31
Tab Tab if($get_in){

Tab Tab Tab $val =~ s/\"/&quot;/g;
Tab Tab Tab $val =~ s/</&lt;/g;
Tab Tab Tab $val =~ s/>/&gt;/g;
Tab Tab }
#end2013/10/31
# 文字コード変換 (Shift-JISコード)
Tab Tab &jcode'convert(*val,'sjis');
Tab Tab $val =~ s/\0/0/g;
Tab Tab $val =~ s/\.\.\//..//g;
Tab Tab
$in{$key} = $val;
Tab }

#GETでのアクセスを拒否
Tab if($in{'ori_ie_id'} eq 'admin' && $in{'mode'} eq 'normal_bbs'){
Tab Tab if ($ENV{'REQUEST_METHOD'} ne "POST" && $admin_pass ne $in{'admin_pass'}) {
Tab Tab Tab &error("不正アクセスのため強制終了されます。0");
Tab Tab }
Tab }elsif($in{'mode'} ne "" && $in{'mode'} ne "houmon" && $in{'mode'} ne "parts_taiou_hyou" && $in{'mode'} ne "itiran" && $in{'mode'} ne "kensaku"){
Tab Tab Tab unless($in{'mode'} eq 'login_view' && $in{'command'} eq 'idousyuuryou'){
Tab Tab Tab Tab
&error("不正アクセスのため強制終了されます。");#追加修正
Tab Tab Tab
}
Tab }
Tab # if($in{'mode'} ne "" && $in{'mode'} ne "houmon" && $in{'ori_ie_id'} ne "admin" && $in{'mode'} ne "parts_taiou_hyou" && $in{'mode'} ne "itiran" && $in{'mode'} ne "kensaku" && $in{'command'} ne "idousyuuryou" && $in{'command'} ne "easySerch"){
Tab Tab # if ($ENV{'REQUEST_METHOD'} ne "POST") {
Tab Tab Tab # &error("不正アクセスのため強制終了されます。");
Tab Tab # }
Tab # }

#パスワードチェック
Tab if ($in{'admin_pass'} ne "$admin_pass"){
Tab Tab if($in{'mode'} ne "" && $in{'mode'} ne "new" && $in{'mode'} ne "parts_taiou_hyou"){
Tab Tab Tab &check_pass;
Tab Tab }
Tab }

}


#######################
# 改造版townの方
# 変更箇所 town_lib.p
#######################

# スクリプトの禁止(タグではありません)先頭またはここで定義koko20131101
$kinnshi_scr = 0;#0で禁止1許可

Tab local($buf, $key, $value, @buf, $cuntkey,$pair,$query);
Tab if ($ENV{'REQUEST_METHOD'} eq "POST") {
# 送信制限
Tab Tab my($size,$remain);
Tab Tab $size = 5000;
Tab Tab $remain = $ENV{'CONTENT_LENGTH'};
Tab Tab if($remain > $size){&error("サイズオーバー");}
Tab Tab read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
Tab } else {
Tab Tab $query = $ENV{'QUERY_STRING'};
Tab Tab $get_in = 1; #koko2013/10/31
Tab Tab if($query =~ m/town_no/ && $query !~ m/name/){&error("不正アクセスです。");}#koko20131101
Tab }
Tab # if($query =~ m/town_no/ && $query !~ m/name/){&error("不正アクセスです。");}#間違えた。koko20131101

Tab if($query){$in_query = 1;}

Tab foreach $pair (split(/&/, $query)) {
Tab Tab ($key, $value) = split(/=/, $pair);
# 文字のデコード
Tab Tab $value =~ tr/+/ /;
Tab Tab # if($key eq 'a_com' && $value !~ /%/){&error("日本語を含んでいない投稿はできません。"); }
Tab Tab $value =~ s/\%([0-9a-fA-F][0-9a-fA-F])/chr(hex($1))/eg;
#koko2013/10/31# エスケープ
Tab Tab if($get_in){
Tab Tab Tab # $value =~ s/&/&amp;/g; 11/10消す
Tab Tab Tab $value =~ s/\"/&quot;/g;
Tab Tab Tab $value =~ s/</&lt;/g;
Tab Tab Tab $value =~ s/>/&gt;/g;
Tab Tab }
Tab Tab if(!$kinnshi_scr && $value =~ m/script/i){ #koko2013/11/01
Tab Tab Tab $value =~ s/\"/&quot;/g;
Tab Tab Tab $value =~ s/</&lt;/g;
Tab Tab Tab $value =~ s/>/&gt;/g;
Tab Tab Tab if(!$get_in){
Tab Tab Tab Tab $value =~ s/&lt;br&gt;/<br>/ig;
Tab Tab Tab }
Tab Tab }
#koko2013/11/10
Tab Tab $value =~ s/\0/0/g; #koko2013/11/10
Tab Tab $value =~ s/\.\.\//..//g; #koko2013/11/10 ../を../とする。
#end2013/10/31
----------------------
Tab while (($key,$value)=each %in){
Tab Tab if($value eq "\r\n" || $value eq "\n" || $value eq "\r"){&error("値がありません");}
Tab Tab $value =~ s/\<\>/&lt;&gt;/g;

Tab Tab
# if(($flag && $key eq "title") || ($flag && $key eq "comento")){ #タグ許可のため
Tab Tab # next;
Tab Tab # }#end20131101 全てのタグが使えるのは不適当と判定

Tab Tab
unless ($key eq "upfile" && $key eq "mode" && $value eq "dokuzi_settei_do" && $key eq "mode" && $value eq "gentei_settei_do"){
----------------------
#GETでのアクセスを拒否 2013/11/13
Tab if($in{'ori_ie_id'} eq 'admin' && $in{'mode'} eq 'normal_bbs'){
Tab Tab if ($ENV{'REQUEST_METHOD'} ne "POST" && $admin_pass ne $in{'admin_pass'}) {
Tab Tab Tab &error("不正アクセスのため強制終了されます。0");
Tab Tab }
Tab }elsif($in{'mode'} ne "" && $in{'mode'} ne "houmon" && $in{'mode'} ne "parts_taiou_hyou" && $in{'mode'} ne "itiran" && $in{'mode'} ne "kensaku"){
Tab Tab if ($ENV{'REQUEST_METHOD'} ne "POST") {
Tab Tab Tab &error("不正アクセスのため強制終了されます。");
Tab Tab }
Tab }
#koko2013/11/10
#----------------------
# 変更箇所 command.pl
#----------------------
Tab Tab }elsif ($m_syubetu eq "告白受信"){
print <<"EOM";
<hr size=1>
<div style="color:#ff3366">○$m_nameさんから交際のお申\し込みがありました$m_hozon</div><br>
$m_com<br><br>
<form method="POST" action="kekkon.cgi">
<input type=hidden name=mode value="assenjo">
<input type=hidden name=command value="easySerch">
<input type=hidden name=serch_name value="$m_name">
<input type=hidden name=name value="$name">
<input type=hidden name=pass value="$pass">
<input type=hidden name=id value="$k_id">
<input type=hidden name=town_no value="$in{'town_no'}">
<input type=submit value="恋人斡旋所で$m_nameさんのプロフィールを見る"></form>
<!-- <a href=kekkon.cgi?mode=assenjo&command=easySerch&serch_name=$m_name&town_no=$in{'town_no'}&name=$name&pass=$pass>恋人斡旋所で$m_nameさんのプロフィールを見る</a> #koko2013/11/10 -->

#----------------------
コメント
<!-- <a href=kekkon.cgi?mode=assenjo&command=easySerch&serch_name=$m_name&town_no=$in{'town_no'}&name=$name&pass=$pass>恋人斡旋所で$m_nameさんのプロフィールを見る</a> #koko2013/11/10 --></div>
のGETをPOSTにして、GETから外してやる。

#----------------------
top_pl

#####街のログを開いて画面展開
Tab if($this_town_no =~ m/\D/){&error("Open Error : no_town");} #koko20131101
Tab $town_data = "./log_dir/townlog".$this_town_no.".cgi";
Tab open(TW,"< $town_data") || &error("Open Error : town_map");
#----------------------
コメント
Open Error : $town_data にて書かれたものがそのまま書き出される。
これによって、不具合が発生する。

#----------------------
admin.cgi

print <<"EOM"; #koko2013/11/10
<div align=center>$in{'town_n'}を作成しました。<br><br>
<a href=$script?town_no=$in{'town_no'}&name=$in{'name'} target="~_blank">[街の確認]</a><br><br>
$modoru<br><br>
EOM
#----------------------
admin2.cgi

print <<"EOM"; #koko2013/11/10
<div align=center>$in{'town_n'}を作成しました。<br><br>
<a href=$script?town_no=$in{'town_no'}&name=$in{'name'} target="~_blank">[街の確認]</a><br><br>
$modoru<br><br>
EOM
#----------------------
コメント
$script?town_no=$in{'town_no'}&name=$in{'name'}
nameを入れてあるか検査しているため$in{'mame'}は何も値を持っていません。

#----------------------

変更済みの明記

#####フッター
sub hooter {
・・・・・・・
print <<"EOM";
<div align=center>
$home_hyouzi
Edit:たっちゃん Ver 5.10.1<br>
<a href="http://shohei.heteml.jp/brassiere/02cgi/09.html" target="~_blank">- $version 2.1 script by brassiere -</a> <a href=$master_kb>■お問い合わせ</a>
</div>
EOM
$versionの後に半角空白2.1半角空白
にて、アップしたことを記録しておいてください。

参考ファイルのダウンロード
     更新ファイル5_10_1

     new ver  全体ファイル5_10_1

もどる