ThinkCMF X2.2.2多處SQL注入漏洞分析
1. 漏洞描述
ThinkCMF是一款基於ThinkPHP+MySQL開發的中文內容管理框架,其中X系列基於ThinkPHP 3.2.3開發,最後更新到2.2.2版本。最近剛好在滲透測試專案中遇到這個CMS,便審了下原始碼發現多處SQL注入漏洞,在Github給專案方提issues後,提交到CVE官方後很快就拿到了分配的多個編號:CVE-2018-19894、CVE-2018-19895、CVE-2018-19896、CVE-2018-19897、CVE-2018-19898。
2.
ThinkCMF X2.2.2(https://github.com/thinkcmf/cmfx)
3. 漏洞分析
3.1 CommentadminController.class.php check、delete方法SQL注入(CVE-2018-19894)
漏洞位於/application/Comment/Controller/CommentadminController.class.php的check、delete方法, 以62行為例,$_POST['ids']引數通過join後,傳遞到where語句中,但並沒有使用where語句的
測試Pyload為
http://127.0.0.1/cmfx/index.php?g=Comment&m=commentadmin&a=check&check=1
POST: ids[]=1&ids[]=2 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
3.2 NavController.class.php中edit_post方法SQL注入(CVE-2018-19895)
跟進`application/Admin/Controller/NavController.class.php`
測試Payload為
http://127.0.0.1/cmfx/index.php?g=Admin&m=nav&a=edit_post
POST: parentid=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
3.3 SlideController.class.php delete方法SQL注入(CVE-2018-19896)
在application/Admin/Controller/SlideController.class.php的93行,delete方法中,$_POST['ids']通過implode方法變成字串,隨後直接拼接進入where語句的in子句中。
測試payload:
http://127.0.0.1/cmfx/index.php?g=Admin&m=slide&a=delete
POST: ids[]=1&ids[]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)
3.4 AdminbaseController.class.php中_listorders方法存在SQL注入(CVE-2018-19897)
_listorders方法用於排序,在很多地方被呼叫。這裡以LinkController.class.php中的listorders()為例進行分析,這裡主要用做友情連結的排序。我們以phpstorm+phpstudy+ xdebug打下斷點,一步步追蹤。測試payload為:
http://127.0.0.1/cmfx/index.php?g=Admin&m=Link&a=listorders
POST: listorders[key][0]=exp&listorders[key][1]=0 and updatexml(1, concat(0x7e,user(),0),1)
首先進入application/Admin/Controller/LinkController.class.php 70行的listorders方法,71行呼叫父類的_listorders()方法。
跟到application/Admin/Controller/LinkController.class.php 166行的_listorders()方法,$_POST['listorders']為二維陣列傳遞給$ids,經過foreach迴圈,輸入的payload進入$data中,仍然為二維陣列,而$data則進入save方法。
跟進到simplewind/Core/Library/Think/Model.class.php 396行的save方法,該方法為thinkphp的核心函式。由於$data不為空,跳過之前的很多判斷直接到452行,$data和$options進入update方法,$data仍然為二維陣列不變。
跟進到simplewind/Core/Library/Think/Db/Driver.class.php 893行的update()方法,$data經過parseSet方法後拼接到$sql中。跟到371行parseSet方法的定義,$data經過foreach迴圈後,$val變為一維陣列,$key為鍵值。而當$val為陣列並且陣列的第一個元素為exp時,$val[1]會和$key直接用等號拼接傳遞到$set,387行陣列$set被逗號implode後拼接到SET子句中。
返回到update方法,SET子句被拼接到$sql中,最終執行的sql語句為
UPDATE `cmf_links` SET `listorder`=0 and updatexml(1, concat(0x7e,user(),0),1) WHERE `link_id` = 'key'
3.5 ArticleController.class.php edit_post方法SQL注入(CVE-2018-19898)
ThinkCMF X2.2.2是基於ThinkPHP 3.2.3開發的,ThinkPHP 3.x版本之前被爆出存在bind注入,這個漏洞就是ThinkPHP3.x注入的典型案例。漏洞位於前臺文章編輯處,測試payload如下:
http://127.0.0.1/cmfx/index.php?g=portal&m=article&a=edit_post
POST: post[id][0]=bind&post[id][1]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)-- -
在application/Portal/Controller/ArticleController.class.php 182行,輸入的引數通過I("post.post")傳遞到$article;跟進到/simplewind/Core/Common/functions.php的I方法定義,在428行,會呼叫think_filter方法對引數進行過濾。
由於正則字元中沒有匹配bind,所以導致了後面的注入漏洞,ThinkPHP官方的修復措施就是在此處匹配時加上了bind。接下來進入典型的資料庫更新操作了,$articles為多維陣列包含payload。
我們F7繼續跟進,會進入simplewind/Core/Library/Think/Model.class.php的where方法,給$this->options['where']賦值後,返回當前物件。隨後進入simplewind/Core/Library/Think/Model.class.php的save方法,隨後執行到update方法
繼續往下,進入到parseSet方法,可以看到傳遞的引數在進行引數繫結操作,其中時間字串被賦於佔位符0,此處會進行迴圈操作,將所有的引數進行繫結。
隨後進入parseWhere函式
分析parseWhere後,發現會執行 parseWhereItem方法,當$exp=='bind'的時候即$val[0]=='bind',會對$val[1]進行拼接,仔細看這裡會多一個`:`,表示為引數繫結時的佔位符。
這裡也就理解為什麼第二個陣列構造的時候需要新增一個數字0,這是由於parseSet方法以及賦值了一個佔位符:0,用來替代時間字串,在隨後的SQL語句執行階段可被用來賦值,否則佔位符沒被賦值會因語法問題產生報錯。
隨後可以看到bindValue將:0繫結為時間字串,實際上這裡有三個引數需要繫結,因此第二個陣列的首位值可以為0、1、2。
執行時產生XPATH異常報錯,得到我們想要的資料。
4. 修復建議
由於ThinkCMF X系列在2.2.2版本後已經不再更新,建議使用者及時升級到Think CMF5。
轉載:https://anquan.baidu.com/article/490 本文來自百度安全SiemPent Team
歡迎關注,有問題一起學習歡迎留言、評論