0x00 前言
該漏洞源於某真實案例,雖然攻擊沒有用到該漏洞,但在分析攻擊之后對該版本的cmf審計之后發現了,也算是有點機遇巧合的味道,我沒去找漏洞,漏洞找上了我XD
thinkcmf 已經非常久遠了,該版本看github上的更新時間已經是4年前了,也就是2014年的時候,那時候我沒學安全呢。。。
0x01 前台sql注入
前台在登錄方法中存在注入,thinkcmf是基於thinkphp3.2寫的,直接看
文件application\User\Controller\LoginController.class.php 方法 dologin
很明顯的注入,通過extract我們可以注冊$where數組,而后直接傳入where方法,沒有經過I方法過濾的引入參數是會引發表達式注入的。
比如這樣子:
這里由於有驗證碼,無法輕易的編寫批量腳本。當然引入打碼工具另說。
注入之后,我們想到的一定是登錄后台了。
那么先了解一下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模式而導致繞過 ,這里就不細說了,懂的人自然懂。
打完收工~