寶塔面板phpMyAdmin未授權(quán)訪問(wèn)安全漏洞是個(gè)低級(jí)錯(cuò)誤嗎?

周日晚,某群里突然發(fā)布了一則消息,寶塔面板的phpmyadmin存在未授權(quán)訪問(wèn)漏洞的緊急漏洞預(yù)警,并給出了一大批存在漏洞的URL:

創(chuàng)新互聯(lián)建站專注于疏附網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供疏附營(yíng)銷(xiāo)型網(wǎng)站建設(shè),疏附網(wǎng)站制作、疏附網(wǎng)頁(yè)設(shè)計(jì)、疏附網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造疏附網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供疏附網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。

隨便點(diǎn)開(kāi)其中一個(gè),赫然就是一個(gè)大大的phpmyadmin后臺(tái)管理頁(yè)面,無(wú)需任何認(rèn)證與登錄。當(dāng)然,隨后各種神圖神事也都刷爆了社交網(wǎng)絡(luò),作為一個(gè)冷靜安全研究者,我對(duì)此當(dāng)然是一笑置之,但是這個(gè)漏洞的原因我還是頗感興趣的,所以本文我們就來(lái)考證一下整件事情的緣由。

一、我們的問(wèn)題究竟是什么?

首先,我先給出一個(gè)結(jié)論:這件事情絕對(duì)不是簡(jiǎn)簡(jiǎn)單單地有一個(gè)pma目錄忘記刪除了,或者寶塔面板疏忽大意進(jìn)行了錯(cuò)誤地配置,更不是像某些人陰謀論中說(shuō)到的官方刻意留的后門(mén)。

我為什么這么說(shuō)?首先,根據(jù)官方的說(shuō)法,這個(gè)漏洞只影響如下版本:

Linux正式版7.4.2

Linux測(cè)試版7.5.13

Windows正式版6.8

這個(gè)版本就是最新版(漏洞修復(fù)版)的前一個(gè)版本。也就是說(shuō),這個(gè)確定的小版本之前的版本面板是不受影響的。我們?cè)囅胍幌拢绻恰昂箝T(mén)”或者官方忘記刪除的目錄,為什么只影響這一個(gè)版本呢?況且寶塔面板發(fā)展了這么久,積累了400萬(wàn)用戶,體系安全性也相對(duì)比較成熟,如果存在這么低劣的錯(cuò)誤或“后門(mén)”,也應(yīng)該早就被發(fā)現(xiàn)了。

經(jīng)過(guò)實(shí)際查看互聯(lián)網(wǎng)上的案例和詢問(wèn)使用了寶塔面板的朋友,我發(fā)現(xiàn)在7.4.2以前的版本中沒(méi)有pma這個(gè)目錄,并且phpmyadmin默認(rèn)情況下認(rèn)證方法是需要輸入賬號(hào)密碼的。所以,寶塔出現(xiàn)這個(gè)漏洞,一定是做過(guò)了下面這兩件事:

新增了一個(gè)pma目錄,內(nèi)容phpmyadmin

phpmyadmin的配置文件被修改了認(rèn)證方式

那么,我們的問(wèn)題就變成了,官方為什么要做這兩處修改,目的究竟是什么?

為了研究這個(gè)問(wèn)題,我們需要先安裝一個(gè)寶塔7.4.2版本。但是,寶塔的安裝是一個(gè)傻瓜化的一鍵化腳本:

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh

并沒(méi)有給到用戶一個(gè)可以選擇版本號(hào)的選項(xiàng),官方的Git也許久沒(méi)更新了,我們?nèi)绾尾拍馨惭b到一個(gè)合適的版本(7.4.2)呢?

二、安裝一個(gè)合適的版本

這當(dāng)然難不倒我。首先,我安裝了最新版的寶塔面板,用的就是上述一鍵化腳本。

安裝的過(guò)程自然沒(méi)什么問(wèn)題,安裝完成后,系統(tǒng)顯示的版本號(hào)是最新版7.4.3,因?yàn)樵诒鲞@個(gè)漏洞以后,官方迅速進(jìn)行了修復(fù)升級(jí)。不過(guò)沒(méi)關(guān)系,我們?nèi)匀豢梢哉业诫x線升級(jí)包:

http://download.bt.cn/install/update/LinuxPanel-7.4.0.zip
http://download.bt.cn/install/update/LinuxPanel-7.4.2.zip
http://download.bt.cn/install/update/LinuxPanel-7.4.3.zip

分別是7.4.0/7.4.2/7.4.3的版本,我們分別下載并解壓,并嘗試將自己的服務(wù)器版本恢復(fù)成漏洞版本7.4.2。

在恢復(fù)代碼之前,我們先將服務(wù)器斷網(wǎng),或者將寶塔設(shè)置成離線模式:

這么做的目的是防止寶塔進(jìn)行自動(dòng)版本更新,避免好不容易恢復(fù)的代碼又自動(dòng)升級(jí)了。

寶塔系統(tǒng)代碼默認(rèn)安裝完是在/www/server/panel,接著我們直接將將壓縮包內(nèi)的panel目錄上傳到這里來(lái),覆蓋掉已有的文件。重啟下寶塔,即可發(fā)現(xiàn)系統(tǒng)版本號(hào)已經(jīng)恢復(fù)成7.4.2了:

還沒(méi)完,我們使用beyond compare打開(kāi)7.4.2和7.4.3的壓縮包代碼,先看看官方是怎么修復(fù)的漏洞:

比較粗暴,直接判斷目錄/www/server/phpmyadmin/pma是否存在,如果存在就直接刪掉。所以,我們雖然恢復(fù)了系統(tǒng)版本代碼,但刪掉的pma已經(jīng)不在了,我們還需要恢復(fù)一下這個(gè)目錄。

方法也很簡(jiǎn)單,/www/server/phpmyadmin下本身存在一個(gè)phpmyadmin目錄,我們直接復(fù)制一下這個(gè)目錄即可:

三、漏洞究竟是怎么回事

有了環(huán)境,我們?nèi)孕杩纯创a。

首先,由于7.4.2是引入漏洞的版本,我們看看官方對(duì)7.4.2的更新日志:

用beyond compare打開(kāi)7.4.0和7.4.2的壓縮包代碼,看看具體增加了哪些代碼:

可見(jiàn),在7.4.2版本中增加了兩個(gè)視圖,分別對(duì)應(yīng)著phpmyadmin和adminer。視圖中用到了panelPHP#start方法,這個(gè)方法其實(shí)也是新加的:

def start(self,puri,document_root,last_path = ''):
        '''
            @name 開(kāi)始處理PHP請(qǐng)求
            @author hwliang<2020-07-11>
            @param puri string(URI地址)
            @return socket or Response
        '''
        ...
        #如果是PHP文件
        if puri[-4:] == '.php':
            if  request.path.find('/phpmyadmin/') != -1:
                ...
                if request.method == 'POST':
                    #登錄phpmyadmin
                    if puri in ['index.php','/index.php']:
                        content = public.url_encode(request.form.to_dict())
                        if not isinstance(content,bytes):
                            content = content.encode()
                        self.re_io = StringIO(content)
                        username = request.form.get('pma_username')
                        if username:
                            password = request.form.get('pma_password')
                            if not self.write_pma_passwd(username,password):
 return Resp('未安裝phpmyadmin')
                if puri in ['logout.php','/logout.php']:
                    self.write_pma_passwd(None,None)
            else:
                ...
      #如果是靜態(tài)文件
        return send_file(filename)

代碼太長(zhǎng),我們不展開(kāi)分析,只我寫(xiě)出來(lái)的部分。在請(qǐng)求的路徑是/phpmyadmin/index.php且存在pma_username、pma_password時(shí),則執(zhí)行self.write_pma_passwd(username,password)。

跟進(jìn)self.write_pma_passwd:

def write_pma_passwd(self,username,password):
        '''
            @name 寫(xiě)入mysql帳號(hào)密碼到配置文件
            @author hwliang<2020-07-13>
            @param username string(用戶名)
            @param password string(密碼)
            @return bool
        '''
        self.check_phpmyadmin_phpversion()
        pconfig = 'cookie'
        if username:
            pconfig = 'config'
        pma_path = '/www/server/phpmyadmin/'
        pma_config_file = os.path.join(pma_path,'pma/config.inc.php')
        conf = public.readFile(pma_config_file)
        if not conf: return False
        rep = r"/\\* Authentication type \\*/(.|\\n)+/\\* Server parameters \\*/"
        rstr = '''/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = '{}';
$cfg['Servers'][$i]['host'] = 'localhost'; 
$cfg['Servers'][$i]['port'] = '{}';
$cfg['Servers'][$i]['user'] = '{}'; 
$cfg['Servers'][$i]['password'] = '{}'; 
/* Server parameters */'''.format(pconfig,self.get_mysql_port(),username,password)
        conf = re.sub(rep,rstr,conf)
        public.writeFile(pma_config_file,conf)
        return True

這個(gè)代碼也很好理解了,如果傳入了username和password的情況下,寶塔會(huì)改寫(xiě)phpmyadmin的配置文件config.inc.php,將認(rèn)證方式改成config,并寫(xiě)死賬號(hào)密碼。

這就是為什么7.4.2版本中pma可以直接訪問(wèn)的原因。

補(bǔ)個(gè)課:

phpmyadmin支持?jǐn)?shù)種認(rèn)證方法,默認(rèn)情況下是Cookie認(rèn)證,此時(shí)需要輸入賬號(hào)密碼;用戶也可以將認(rèn)證方式修改成Config認(rèn)證,此時(shí)phpmyadmin會(huì)使用配置文件中的賬號(hào)密碼來(lái)連接mysql數(shù)據(jù)庫(kù),即不用再輸入賬號(hào)密碼。

四、官方做這些動(dòng)作的原因

其實(shí)各位看官看到這里肯定腦子里還是一團(tuán)漿糊,這些代碼究竟意味著什么呢?為什么官方要將認(rèn)證模式改成config模式?

是很多漏洞分析文章的通病,這些文章在出現(xiàn)漏洞后跟一遍漏洞代碼,找到漏洞發(fā)生點(diǎn)和利用方法就結(jié)束了,并沒(méi)有深入研究開(kāi)發(fā)為什么會(huì)這么寫(xiě),那么下次你還是挖不出漏洞。

所以,這里思考一下,我們現(xiàn)在起碼還有下列疑問(wèn):

在7.4.2版本以前,用戶是如何使用phpmyadmin的?

寶塔為什么要在7.4.2版本增加phpmyadmin有關(guān)的視圖?

寶塔為什么要將phpmyadmin認(rèn)證模式改成config?

我們?nèi)绾螐?fù)現(xiàn)這個(gè)漏洞?

第一個(gè)問(wèn)題,我們其實(shí)可以簡(jiǎn)單找到答案。在正常安裝寶塔最新版7.4.3時(shí),我們點(diǎn)擊寶塔后臺(tái)的phpmyadmin鏈接,會(huì)訪問(wèn)到這樣一個(gè)路徑:

7.4.3版本為了修復(fù)這個(gè)漏洞,回滾了部分代碼,所以這種方式其實(shí)就是7.4.2以前版本的phpmyadmin的訪問(wèn)方式:通過(guò)888端口下的一個(gè)以phpmyadmin_開(kāi)頭的文件夾直接訪問(wèn)phpmyadmin。

這種老的訪問(wèn)方法中,888端口是一個(gè)單獨(dú)的Nginx或Apache服務(wù)器,整個(gè)東西是安全的,訪問(wèn)也需要輸入賬號(hào)密碼。

但是這種訪問(wèn)方法有些麻煩,需要額外開(kāi)放888端口,而且每次登陸都要重新輸入密碼。所以,官方開(kāi)發(fā)人員提出了一種新的做法,在寶塔后端的python層面轉(zhuǎn)發(fā)用戶對(duì)phpmyadmin的請(qǐng)求給php-fpm。這樣有三個(gè)好處:

直接在python層面做用戶認(rèn)證,和寶塔的用戶認(rèn)證進(jìn)行統(tǒng)一,不需要多次輸入mysql密碼

也不需要再對(duì)外開(kāi)放888端口了

使用phpmyadmin也不再依賴于Nginx/Apache等服務(wù)器中間件了

這就是為什么寶塔要在7.4.2增加phpmyadmin有關(guān)的視圖的原因,這個(gè)視圖就是一個(gè)phpmyadmin的代理,做的事情就是轉(zhuǎn)發(fā)用戶的請(qǐng)求給php-fpm。

用戶在第一次使用這種方式登錄時(shí),系統(tǒng)會(huì)自動(dòng)發(fā)送包含了Mysql賬號(hào)密碼的數(shù)據(jù)包,寶塔后端會(huì)捕捉到此時(shí)的賬號(hào)密碼,填入phpmyadmin的配置文件,并將認(rèn)證方式改成config。對(duì)于用戶來(lái)說(shuō),感受到的體驗(yàn)就是,不再需要輸入任何Mysql密碼即可使用phpmyadmin了。

這的確給用戶的使用帶來(lái)了更好的體驗(yàn)。

五、漏洞復(fù)現(xiàn)

此時(shí)我們應(yīng)該還有個(gè)疑問(wèn):既然官方目的是“直接在python層面做用戶認(rèn)證,和寶塔的用戶認(rèn)證進(jìn)行統(tǒng)一”,那么仍然是有認(rèn)證的呀?為什么會(huì)出現(xiàn)未授權(quán)訪問(wèn)漏洞呢?

我們可以來(lái)復(fù)現(xiàn)一下這個(gè)漏洞。首先,我們以系統(tǒng)管理員的身份登錄寶塔后臺(tái),來(lái)到數(shù)據(jù)庫(kù)頁(yè)面,點(diǎn)擊“phpMyAdmin”按鈕,會(huì)彈出如下模態(tài)框:

這個(gè)里面有兩種訪問(wèn)模式,“通過(guò)Nginx/Apache/OIs訪問(wèn)”是老版本的訪問(wèn)方式,“通過(guò)面板安全訪問(wèn)”就是7.4.2新增加的代理模式。

我們點(diǎn)擊“通過(guò)面板安全訪問(wèn)”,并抓包,會(huì)抓到這樣一個(gè)數(shù)據(jù)包:

寶塔前端將我們的Mysql賬號(hào)密碼填好了直接發(fā)給phpmyadmin。又因?yàn)槲覀兦懊娣治鲞^(guò)的那段代碼,后臺(tái)將賬號(hào)密碼直接寫(xiě)入了phpmyadmin配置文件,來(lái)做到免認(rèn)證的邏輯。

如果一個(gè)未認(rèn)證的用戶,直接訪問(wèn)http://ip:8888/phpmyadmin/index.php呢?會(huì)被直接重定向到登錄頁(yè)面:

如果僅僅是這樣,這個(gè)過(guò)程是不存在漏洞的。但是,官方開(kāi)發(fā)人員犯了一個(gè)錯(cuò)誤,他將pma應(yīng)用放在了/www/server/phpmyadmin目錄下,而這個(gè)目錄原本是老的phpmyadmin訪問(wèn)方式所使用的Web根目錄。

這意味著,我通過(guò)老的888端口+pma目錄,可以訪問(wèn)到新的phpmyadmin,而新的phpmyadmin又被官方修改了配置文件,最終導(dǎo)致了未授權(quán)訪問(wèn)漏洞:

所以,如何解決這個(gè)問(wèn)題呢?也很簡(jiǎn)單,只需要將pma移到其他目錄去即可。

六、總結(jié)

我們來(lái)做個(gè)總結(jié)。

首先,寶塔面板絕對(duì)不是弱智,這個(gè)漏洞不是簡(jiǎn)簡(jiǎn)單單的放了一個(gè)未授權(quán)的pma在外面忘記刪。這其實(shí)會(huì)打很多人臉,因?yàn)榇蟛糠秩苏J(rèn)為這只是個(gè)簡(jiǎn)單的phpmyadmin未授權(quán)訪問(wèn)漏洞,并對(duì)寶塔進(jìn)行了一頓diss,沒(méi)有想到這后面其實(shí)是一個(gè)復(fù)雜的邏輯錯(cuò)誤。

其次,用戶體驗(yàn)和安全絕對(duì)是不沖突的,我十分不喜歡為了保障安全而閹割用戶體驗(yàn)的做法。所以希望寶塔官方不會(huì)因?yàn)檫@次的漏洞事件而徹底將代碼回滾(據(jù)說(shuō)7.4.3的更新只是臨時(shí)解決方案),該改進(jìn)的地方還是要改進(jìn)。

我有數(shù)年不再使用Linux面板了,這次也算重新體驗(yàn)了一下2020年的Linux面板,個(gè)人感覺(jué)寶塔看外在其實(shí)是一個(gè)比較注重安全的系統(tǒng),比如自動(dòng)生成的用戶密碼、用戶名和密碼的策略、默認(rèn)的Php安全配置、自動(dòng)的版本更新等等,相比于很多國(guó)內(nèi)其他的商業(yè)系統(tǒng),絕對(duì)屬于有過(guò)之而無(wú)不及了。但是看代碼其實(shí)需要改進(jìn)的地方還有很多,這個(gè)以后有機(jī)會(huì)再細(xì)說(shuō)吧。

本文來(lái)自公眾號(hào):https://mp.weixin.qq.com/s/3ZjwFo5gWlJACSkeYWQLXA

新聞名稱:寶塔面板phpMyAdmin未授權(quán)訪問(wèn)安全漏洞是個(gè)低級(jí)錯(cuò)誤嗎?
標(biāo)題網(wǎng)址:http://www.muchs.cn/article28/cjjhjp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、電子商務(wù)定制網(wǎng)站、品牌網(wǎng)站建設(shè)、用戶體驗(yàn)標(biāo)簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化