当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2014-068853

漏洞标题:Phpyun注入漏洞二

相关厂商:php云人才系统

漏洞作者: ′雨。

提交时间:2014-07-17 15:56

修复时间:2014-10-15 16:00

公开时间:2014-10-15 16:00

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-07-17: 细节已通知厂商并且等待厂商处理中
2014-07-17: 厂商已经确认,细节仅向厂商公开
2014-07-20: 细节向第三方安全合作伙伴开放
2014-09-10: 细节向核心白帽子及相关领域专家公开
2014-09-20: 细节向普通白帽子公开
2014-09-30: 细节向实习白帽子公开
2014-10-15: 细节向公众公开

简要描述:

刚在官网下的。
前台注入。 可以直接出管理员的帐号和密码。
无视360webscan。

详细说明:

本来以为挖不到了 无聊翻翻文件看看。 翻到了上次那个注入的文件。
model/register.class.php

function regsave_action(){
$_POST=$this->post_trim($_POST);
$_POST['username']=iconv("utf-8","gbk",$_POST['username']);
$_POST['unit_name']=iconv("utf-8","gbk",$_POST['unit_name']);


省略点

ip = $this->obj->fun_ip_get();
$data['username']=$_POST['username'];
$data['password']=$pass;
$data['moblie']=$_POST['moblie'];
$data['email']=$_POST['email'];
$data['usertype']=$_POST['usertype'];
$data['status']=$satus;
$data['salt']=$salt;
$data['reg_date']=time();
$data['reg_ip']=$ip;
$data['qqid']=$_SESSION['qq']['openid'];
$data['sinaid']=$_SESSION['sinaid'];

$userid=$this->obj->insert_into("member",$data);


主要看到这里ip = $this->obj->fun_ip_get();
一开始就是想的会不会有很古老的xff洞? 后面想了想不太可能把 phpyun这程序目测还算不错的。
可是还是看了看这函数。
然后看到两个文件里面都声明了这函数
1 在 /include/public.function.php 中

function fun_ip_get() {
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) {
$ip = getenv("HTTP_CLIENT_IP");
} else
if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
} else
if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) {
$ip = getenv("REMOTE_ADDR");
} else
if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) {
$ip = $_SERVER['REMOTE_ADDR'];
} else {
$ip = "unknown";
}
$preg="/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/";
if(preg_match($preg,$ip)){

return ($ip);
}


这个文件里面的这函数验证了。
2 /model/class/action.class.php

function fun_ip_get() {
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) {
$ip = getenv("HTTP_CLIENT_IP");
} else
if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
} else
if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) {
$ip = getenv("REMOTE_ADDR");
} else
if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) {
$ip = $_SERVER['REMOTE_ADDR'];
} else {
$ip = "unknown";
}
return ($ip);


而这/model/class/action.class.php文件里面的却没验证ip是否合法。。
而刚才调用的函数 就是调用的这文件里面的。。。。。
碉堡了。。
继续在model/register.class.php里面看。

$ip = $this->obj->fun_ip_get();
$data['username']=$_POST['username'];
$data['password']=$pass;
$data['moblie']=$_POST['moblie'];
$data['email']=$_POST['email'];
$data['usertype']=$_POST['usertype'];
$data['status']=$satus;
$data['salt']=$salt;
$data['reg_date']=time();
$data['reg_ip']=$ip;
$data['qqid']=$_SESSION['qq']['openid'];
$data['sinaid']=$_SESSION['sinaid'];

$userid=$this->obj->insert_into("member",$data);


然后就带入到了insert当中

function insert_into($table,$data=array()){
$value="";
$FieldSQL = "SELECT `COLUMN_NAME` FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$this->def.$table."'";
$Fquery = $this->db->query($FieldSQL);
while($Frow=$this->db->fetch_array($Fquery)){
$Freturn[]=$Frow;
}
if(is_array($Freturn))
{
foreach($Freturn as $Fkey=>$Fval)
{
$fields[] = $Fval['COLUMN_NAME'];
}
if(is_array($data)){
foreach($data as $key=>$v){
if(in_array($key,$fields))
{
$v = $this->FilterStr($v);
$value[]="`".$key."`='".mysql_real_escape_string($v)."'";


可是在这里 mysql_real_escape_string 转义了 没办法用。
在找找其他哪个文件调用了这函数。
在model/login.class.php中

function loginsave_action()
{
$username=iconv("utf-8","gbk",$_POST['username']);
if($_COOKIE['uid']!=""&&$_COOKIE['username']!="")
{
$this->ajaxlogin($_POST['comid'],"您已经登陆了,您不是个人用户!");
echo "您已经登录了!";die;
}
if($_POST['path']!="index")
{
if(strstr($this->config["code_web"],'前台登陆'))
{
if(md5($_POST["authcode"])!=$_SESSION["authcode"])
{
$this->ajaxlogin($_POST['comid'],"验证码错误!");
echo "验证码错误!";die;
}
}
}


省略一点

$time = time();

$ip = $this->obj->fun_ip_get();
$this->obj->DB_update_all("member","`login_ip`='$ip',`login_date`='$time',`login_hits`=`login_hits`+1","`uid`='".$user['uid']."'");
$this->unset_cookie();
$this->add_cookie($user['uid'],$user['username'],$user['salt'],$user['email'],$user['password'],$_POST['usertype']);


然后在这里
$this->obj->fun_ip_get(); 再次调用了这函数,
进入DB_update_all

function DB_update_all($tablename, $value, $where = 1){
$SQL = "UPDATE `" . $this->def . $tablename . "` SET $value WHERE $where";
$this->db->query("set sql_mode=''");
$return=$this->db->query($SQL);
return $return;
}


这函数里没有转义 所以可以直接来注入了。
而且由于可控的是在set位 所以我们可以想update 哪个column 就update哪个column。
这里我们update一下email.
再来看一下360webscan。

foreach($_GET as $key=>$value) {
webscan_StopAttack($key,$value,$getfilter,"GET");
}
}
if ($webscan_post) {
foreach($_POST as $key=>$value) {
webscan_StopAttack($key,$value,$postfilter,"POST");
}
}
if ($webscan_cookie) {
foreach($_COOKIE as $key=>$value) {
webscan_StopAttack($key,$value,$cookiefilter,"COOKIE");
}
}
if ($webscan_referre) {
foreach($webscan_referer as $key=>$value) {
webscan_StopAttack($key,$value,$postfilter,"REFERRER");
}
}
}


检测了get post cookie
server里面只检测了referer
所以 xff的话 不用管360。

漏洞证明:

p2.jpg


然后注销账户 重新登录一次。

p3.jpg

修复方案:

检测是否合法。

版权声明:转载请注明来源 ′雨。@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:10

确认时间:2014-07-17 15:59

厂商回复:

感谢您的支持,我们会及时发布更新补丁!

最新状态:

暂无