一改化、前言
朋友給了我一個授權(quán)的站點,讓我?guī)兔y試枉昏,并記錄整體流程陈肛。
從主站測試無果。通過信息收集兄裂,發(fā)現(xiàn)服務(wù)器還有一個疑似測試使用的旁站句旱。
在GitHub上找到旁站源碼阳藻,通過審計發(fā)現(xiàn)一個任意文件讀取漏洞。讀取數(shù)據(jù)庫配置文件前翎,連接數(shù)據(jù)庫稚配,發(fā)現(xiàn)主站的管理員賬號密碼,最終getshell港华。
二、主站測試
前臺為登錄頁面:
隨手試了一下后臺路徑Admin午衰,發(fā)現(xiàn)路徑?jīng)]改立宜,而且登錄的提示報錯可以枚舉用戶名,可知管理員賬號就是Admin:
.查看登錄的請求包密碼臊岸,發(fā)現(xiàn)沒有經(jīng)過加密橙数,那就隨手爆破一波碰碰運氣——不出意外沒有成功:
隨手輸入一個路徑,看到報錯信息帅戒,可以知道框架是Thinkphp灯帮,而且是有rce的版本:
拿起Payload一通亂打,發(fā)現(xiàn)沒反應(yīng)逻住,應(yīng)該是漏洞被修復(fù)了钟哥。
隨后注冊賬號,登錄之后隨便點了幾個功能瞎访,都沒什么可以利用的地方腻贰。這套模板之前是有很多漏洞的,但是隨著后面慢慢更新扒秸,這些漏洞基本都被修復(fù)了播演。
三、旁站測試
既然主站沒辦法直接打伴奥,就轉(zhuǎn)變一下思路写烤,老老實實從信息收集開始。
找到一個旁站拾徙,Onethink洲炊,沒有什么數(shù)據(jù),看著像是測試用的:
后臺路徑依舊沒改锣吼,Admin.php选浑,不過也進(jìn)不去,沒什么用:
這套框架已經(jīng)出了很久玄叠,也停更了很久古徒。搜索了一下,似乎有sql注入漏洞和緩存文件getshell读恃,但無法復(fù)現(xiàn)隧膘,可能因為版本不同代态。
之后又在Github搜了一下,可以找到源碼疹吃,干脆自己動手蹦疑,豐衣足食。
下載完打開代碼萨驶,隨便找?guī)讉€文件拼接路徑歉摧,測試一下是不是同樣的代碼。
確認(rèn)完后開始看代碼腔呜,先直接全局搜索叁温,各種敏感函數(shù)都搜一遍,發(fā)現(xiàn)有call_user_func_array:
從第一個開始看核畴,iswaf.php文件膝但,call_user_func_array在execute方法里,代碼如下:
functionexecute($function,$args = '',$path = 'extensions') {
$function = basename($function);
$path= basename($path);
self::$model = $function;
if(file_exists(iswaf_root.$path.'/'.$function.'.php')) {
include_once iswaf_root.$path.'/'.$function.'.php';
$classname = 'plus_'.$function;
$class = new $classname;
self::$models[] = $function;
if(!is_array($args)) $args = array($args);
$a = call_user_func_array(array($class, $function),$args);
self::debuginfo($function);
return $a;
}
}
追蹤execute方法谤草,有個runapi方法調(diào)用跟束,代碼如下:
function runapi() {
if(isset($_POST['action']) && isset($_POST['args']) &&($_POST['key'] == md5(iswaf_connenct_key) || self::$mode == 'debug')){
$get['args'] =unserialize(self::authcode($_POST['args'],'DECODE'));
$get['function'] = $_POST['action'];
if($get['function']) {
if(!isset($_GET['debug']) &&!isset($_GET['key']) && $_GET['key'] !==md5(iswaf_connenct_key)) {
echoself::authcode(self::execute($get['function'],$get['args'],'apis'),'ENCODE');
}else{
print_r(unserialize(self::execute($get['function'],$get['args'],'apis')));
}
exit;
}
}
}
那么下一步要看一下怎么調(diào)用這個runapi方法。runapi方法屬于iswaf類丑孩,而在iswaf類內(nèi)有一行代碼直接調(diào)用了這個方法冀宴,iswaf文件在最后會new一個對象且調(diào)用到那個方法:
所以只要直接訪問iswaf文件,就可以調(diào)用runapi方法嚎杨。
runapi方法接收三個請求參數(shù)花鹅,分別是action、args和key枫浙,然后對三個參數(shù)進(jìn)行判斷刨肃,先判斷請求體的action、args不為空箩帚,key是md5加密的iswaf_connect_key真友,這個是寫死的,定義在conf.php里面:
滿足了這幾個條件后紧帕,就是處理請求里的action和args盔然。action沒有做特殊處理,只是做了個賦值是嗜。
args走了反序列化和一層authcode方法加密愈案,所以這里的args參數(shù)是要經(jīng)過序列化的。至于加密方法authcode鹅搪,代碼太長了站绪,就不貼出來了,反正整個方法直接拉出來用就行了丽柿。
接下來看下一個判斷恢准,是_GET請求參數(shù)debug和key都為空和key值敏沉,如果走if里的代碼果正,就是加密,這里要走的是else里的代碼赦抖,所以隨便加個debug=1或者key=1舱卡。最后請求包大概就是這樣:
到此,runapi方法就分析完畢了队萤,構(gòu)造好這樣的請求包后,就會走到execute方法里面矫钓。繼續(xù)看一下execute方法:
依舊是有三個參數(shù)要尔,function和args可以通過runapi方法控制,第三個參數(shù)是寫死的:
下面這里就重點關(guān)注call_user_func_array了新娜,先通過if判斷文件是否存在赵辕,iswaf_root文件目錄路徑,path前面已經(jīng)看到是apis概龄,function可控还惠。
然后包含文件,拼接plus_和function私杜,之后和args作為參數(shù)傳遞給call_user_func_array執(zhí)行蚕键,看一下apis目錄下的文件和代碼,可以發(fā)現(xiàn)這里是專門用于執(zhí)行這些文件代碼的:
而這里面又有一個write_config方法衰粹,可以寫入配置文件:
但是測試了半天锣光,因為引號會被轉(zhuǎn)義,死活繞不過去铝耻,只能放棄誊爹。最后看到一個讀取文件的方法:
沒有任何過濾:
先嘗試讀一下數(shù)據(jù)庫配置文件:
測試連接,發(fā)現(xiàn)支持外聯(lián)瓢捉,并且主站的數(shù)據(jù)庫也在里面频丘。
最后,在其中找到管理員賬號密碼泡态,解密哈希搂漠,進(jìn)入后臺,發(fā)現(xiàn)有任意文件上傳漏洞沒有修改兽赁,可以直接上傳任意文件状答,這些操作都很常規(guī)冷守,就不截圖了。
四惊科、總結(jié)
整體流程走下來拍摇,感覺自己還是運氣比較好,目標(biāo)數(shù)據(jù)庫開了外聯(lián)馆截,并且找到了主站管理員密碼充活。
目標(biāo)也是百密一疏,前臺漏洞都修復(fù)了蜡娶,可能覺得后臺一般進(jìn)不去混卵,就沒有修復(fù)漏洞。
個人最大的體會窖张,還是測試過程需要多做一些信息收集工作幕随,說不定在某個地方就會柳暗花明。