0x00 前言php
該漏洞源於某真實案例,雖然攻擊沒有用到該漏洞,但在分析攻擊以後對該版本的cmf審計以後發現了,也算是有點機遇巧合的味道,我沒去找漏洞,漏洞找上了我XDgit
thinkcmf 已經很是久遠了,該版本看github上的更新時間已是4年前了,也就是2014年的時候,那時候我沒學安全呢。。。github
0x01 前臺sql注入算法
前臺在登陸方法中存在注入,thinkcmf是基於thinkphp3.2寫的,直接看sql
文件application\User\Controller\LoginController.class.php 方法 dologinthinkphp
很明顯的注入,經過extract咱們能夠註冊$where數組,然後直接傳入where方法,沒有通過I方法過濾的引入參數是會引起表達式注入的。shell
好比這樣子:數據庫
這裏因爲有驗證碼,沒法輕易的編寫批量腳本。固然引入打碼工具另說。數組
注入以後,咱們想到的必定是登陸後臺了。安全
那麼先了解一下thinkcmf的管理員密碼是怎麼加密的。
看到 install\index.php 文件的 sp_password 方法
解釋一下,$pre就是表前綴,$pw是密碼,意思是
存儲在數據庫的密碼 = 表前綴md5的前12位+密碼md5+表前綴md5的後四位
好比值爲c535018ee946e10adc3949ba59abbe56e057f20f883e89af 存儲在數據庫的密碼。
那麼拆分一下就是
c535018ee946(表前綴md5的前12位)
e10adc3949ba59abbe56e057f20f883e(密碼md5)
89af(表前綴md5的後四位)
知道所謂的加密算法以後,咱們就能夠輕易獲取到管理員密碼的md5值,經過碰撞md5值的形式獲取到管理員的真實密碼。
如今咱們能夠登陸上後臺了,可登陸後臺以後要怎麼getshell呢?
仔細分析了一下thinkcmf的後臺,彷佛沒有能夠getshell的地方。
0x02 權限驗證處的任意代碼執行
認真看了看代碼,發現後臺的一些操做會有權限驗證,而跟蹤權限驗證代碼的時候發現了一個eval的代碼塊。
看到權限驗證處application\Common\Lib\iAuth.class.php check 方法
使用了eval來引入變量,那麼這個$command是否可控呢?
經分析其來源於sp_auth_rule表中的condition字段,備註爲規則附加條件
而這些數據在安裝的時候就早已經寫入到數據庫中了,除非咱們有辦法能夠來修改這裏的值?
是的,前面的sql注入排上用場了。
thinkphp 自 3系列開始就使用pdo做爲鏈接數據庫的驅動,而這裏這個注入不涉及到參數綁定等問題,那麼咱們就能夠利用它來執行多語句,插入數據或者修改數據了。
簡單測試一下,好比修改一下後臺管理員的user_email字段。
查看數據庫,成功修改
多語句執行能夠爲咱們省下不少事,好比密碼過於複雜沒法猜解出明文時,咱們能夠直接修改密碼的hash值爲咱們想要的。
分析一下權限驗證的代碼,它是怎麼觸發的?
隨便找了個須要登陸後臺的文件好比 application\Portal\Controller\AdminPageController.class.php
該controller繼承於AdminbaseController,跟蹤下去
而在AdminbaseController初始化的函數中,發現了檢測權限的代碼,跟進
發現若是$uid是1的話就直接返回了,這個$uid其實就是數據庫裏面的id字段值,也就是說要觸發權限驗證就必須是一個低權限的用戶。
繼續走,若是訪問的不是url爲admin/index/index 就會進行鑑權,跟進sp_auth_check方法
最終來到了咱們的check方法。
具體意思都寫在解釋裏面了,看到eval代碼塊,咱們只要閉合掉左括號,便可引入咱們的惡意代碼。
那麼整個利用過程就是登陸一個低權限的用戶,經過sql注入寫入代碼到咱們能夠訪問的url的condition字段中。
好比我填加了一個低權限的用戶hack,他擁有內容管理的權限
對應他可以訪問的url有
那麼咱們只要在sp_auth_rule表中對應的url的condition字段插入代碼,而後登錄該用戶訪問該url便可觸發代碼執行。
好比咱們經過sql注入插入一段執行phpinfo的代碼
payload:
where[id][0]=exp&where[id][1]=in (1);update sp_auth_rules set `condition`='1);phpinfo();die();//' where id=30#
請求
查看一下表sp_auth_rule,成功插入
那麼後臺登錄用戶hack以後,訪問url
http://127.0.0.1/index.php?g=Portal&m=AdminPage&a=add
便可看到phpinfo執行了
而在以後的研究中,我發現此處權限驗證的代碼來自於thinkphp 自身。
看到文件simplewind\Core\Library\Think\Auth.class.php getAuthList方法的代碼
是否是有種似曾相識的感受,是的就是thinkcmf根據tp的改寫的。
那麼這裏就引伸出來一個審計點:
tp3框架中若是使用了auth類來驗證權限,且有注入點,那麼是能夠嘗試去審計一下任意代碼執行。
相似的例子,暫時沒看到,之後看到了更新上來。
0x03 總結
總結一下利用:
經過前臺的sql注入,獲取到後臺權限(獲取管理員密碼,或者修改管理員hash值),登錄進後臺,添加低權限用戶,再經過sql注入來注入代碼。登錄低權限用戶,訪問注入了代碼的url,便可觸發任意代碼執行。
而在實際中,每每是已經有了低權限的用戶,咱們只須要觀察用戶可以訪問的URL,直接注入代碼便可,免去了添加低權限用戶的步驟。
整個利用構造下來仍是比較有趣的,不完美的是仍是須要登陸後臺,由於不少網站或許會把後臺隱藏掉,可是也有可能會由於不理解tp支持的url模式而致使繞過 ,這裏就不細說了,懂的人天然懂。
打完收工~