Metinfo6.0.0-6.1.2前臺注入漏洞生命線
*本文作者:Mochazz,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載
大家好,我是 紅日安全-七月火 ,這篇文章是以往挖掘的 Metinfo 漏洞,鑑於官方已修復,遂將分析文章放出。
前言
這個前臺注入漏洞存在已久,從MetInfo釋出的6.0版本就存在,且後來官方的修復程式碼,也可以直接繞過。筆者於7月份提交了當時最新 MetInfo 6.1.0版本SQL%E6%B3%A8%E5%85%A5/">SQL注入漏洞,該漏洞直到6.1.3版本才被修復。如下漏洞分析,權當思路分享。
漏洞分析
2018-1-29, MetInfo 官方重寫後臺及前臺程式碼,併發布了 MetInfo6.0。 然而這一新版程式碼,卻存在一個嚴重的前臺SQL注入漏洞,我們來看一下具體詳情。
首先漏洞存在於 app\system\message\web\message.class.php 檔案中,變數 {$_M[form][id]} 直接拼接在 SQL 語句中,且驗證碼檢測函式是在 SQL 語句查詢之後,這也就造成了我們可以無視驗證碼檢測函式,進行 SQL 注入。具體問題函式程式碼如下:
那麼實際上,開發者是有考慮到 SQL 注入問題,並寫了 sqlinsert 來檢測 SQL 注入攻擊的,甚至還對 {$_M[form][id]} 進行了 is_numeric 判斷處理,但是為什麼最終還是存在 SQL 注入呢?下面我們具體來看看 {$_M[form][id]} 變數的獲取過程。
想要觸發這個 SQL 注入漏洞,我們可以通過前臺的 線上留言 和 線上反饋 兩個功能來觸發。我們這裡先分析 線上留言 處的程式邏輯。我們填寫留言處的表單,並在最下方新增上 id 欄位,其值對應我們的攻擊 payload ,具體如下:(為了避免圖片太長,我把一些引數的值給略去)
然後我們在 message\index.php 檔案中打下斷點,會發現在 app\system\include\class\common.class.php 的構造方法中,載入了表單,具體的呼叫鏈即程式碼如下:
此時 this 物件指的是 web 類,我們繼續跟進 web 類的 load_form 方法。
我們會發現 common 基類的 load_form 方法將 GET 、 POST 、 COOKIE 獲取的所有資料存放在 $_M['form'] 中,資料僅用 daddslashes 函式處理。而 web 類的 load_form 方法重寫了 common 類的 load_form 方法,對 $_M['form'] 中的所有資料進行了 sqlinsert 處理,並且在後面判斷 $_M['form']['id'] 是否為數字,如果不是數字就直接設定為空字串。這些過濾函式具體程式碼如下:
可以看到 sqlinsert 函式對 sleep 關鍵字進行了處理,但是我們還是可以使用 MYSQL 中的 benchmark 函式輕鬆繞過(這兩個函式都能利用在時間盲注中,具體可以參考: ofollow,noindex" target="_blank">https://xz.aliyun.com/t/2288 )。但是我們的 payload 卻繞不過 is_numeric 函式,所以此時的 $_M['form']['id'] 會被設定成空字串。那為什麼還存在 SQL 攻擊呢?我們接著看程式邏輯。
在跟程序序的過程中,我們會發現在執行完 load::sys_class(‘upfile’, ‘new’) 程式碼後, $_M['form']['id'] 的值又變成了我們傳入的 payload ,這說明這裡面一定是又重新進行了表單賦值。
果不其然,程式中載入的 upfile 類又重新載入了 $_M['form'] 的值,而且並沒有進行除了基類中 daddslashes 方法以外的消毒處理,這也是造成 SQL 注入的原因。
我們可以根據上面的漏洞原理,輕鬆的寫出攻擊指令碼:
接著,我們再來對比一下5月份的修復程式碼,此時 MetInfo 官方並沒有更新版本號,而是偷偷修復了程式碼,修復程式碼如下右圖:
可以清晰的看見 daddslashes 方法開始對每個引數進行 sqlinsert 處理。而上面我們說過,這個消毒函式是可以繞過的,所以我們依然可以進行 SQL 注入。
雖然可以進行盲注,但是還是太耗費時間了,我們是否有辦法將其轉換成布林盲注呢?答案是可以的,接下來我們就來看看,如何將這一處時間盲注變成布林盲注。
在 app\system\message\web\message.class.php 檔案中,我們會發現如果SQL語句查詢結果中的 value 欄位非空,則會進行驗證碼的檢測,否則會直接返回 反饋已經被關閉 。
這樣子,我們就可以根據不同的返回結果,進行布林盲注。現在我們來看一下如何找到滿足查詢結果中的 value 欄位非空的 columnid ,直接在 MYSQL 中做如下查詢:
這樣子我們就找到了兩個可用的 columnid 最終我們同樣可以寫出攻擊指令碼,如下:
我們再來看另一處注入點,前面我們分析的是 線上留言 處的 SQL 注入問題,這次我們要分析 線上反饋 處的 SQL 注入,漏洞的成因都是類似的。不過在利用這個漏洞時,我們需要經過 feedback 類 check_field 方法的檢測。
這裡實際上可用的 id 有兩個,如下:
例如這裡我想利用 id=71 ,那麼需要構造如下資料包,才會進入漏洞觸發處。
現在繞過了 check_field 方法的檢測,我們就順利來到了觸發 SQL 注入漏洞的 feedback 累的 add 方法,其位置在 app\system\feedback\web\feedback.class.php ,具體程式碼如下:
我們會發現這次的驗證碼校驗,位置在注入點前面,所以利用起來比較麻煩。這裡我們可以使用爆破驗證碼結合時間盲注的方式進行攻擊,用以下程式生成全排列驗證碼字典:
from itertools import product rand_chrs="A2B3C4D5E6F7G8H9iJKLMNPQRSTUVWXYZ" with open("codes.txt",'w') as f: for code in product(rand_chrs,rand_chrs,rand_chrs,rand_chrs): code = ''.join(list(code)) print(code) f.write(code+'\n')
但是這樣的攻擊成本還是太高了,如果大家會機器學習,可以加入相關演算法來自動識別驗證碼。
最後我們來看一下 MetInfo 6.1.3 最新版的修復情況如何,具體情況如下 DIFF 圖:
結語
文章中提到的這個漏洞點,實際上也可以從其他入口點進行觸發,之前也已經有師傅放出分析文章,漏洞的成因都是一樣的,具體可以參閱文末的相關文章,這裡不再贅述。本文分析到此結束,如有不當還望各位斧正。另外,我們團隊正在招收程式碼審計成員,如果您在這方面有豐富的經驗,歡迎加入我們。(可以發郵件至:[email protected])。對程式碼審計感興趣的朋友,也可以關注我們的程式碼審計專案: PHP-Audit-Labs" ref="" rel="nofollow,noindex" target="_blank"> PHP-Audit-Labs