您好,登錄后才能下訂單哦!
原文鏈接: https://paper.seebug.org/1006/
KDE Frameworks是一套由KDE社群所編寫的庫及軟件框架,是KDE Plasma 5及KDE Applications 5的基礎(chǔ),并使用GNU通用公共許可證進(jìn)行發(fā)布。其中所包含的多個(gè)獨(dú)立框架提供了各種常用的功能,包括了硬件集成、文件格式支持、控件、繪圖功能、拼寫檢查等。KDE框架目前被幾個(gè)Linux發(fā)行版所采用,包括了Kubuntu、OpenMandriva、openSUSE和OpenMandriva。
2019年7月28日Dominik Penner(@zer0pwn)發(fā)現(xiàn)了KDE framework版本<=5.60.0時(shí)存在命令執(zhí)行漏洞。
2019年8月5日Dominik Penner在Twitter上披露了該漏洞,而此時(shí)該漏洞還是0day漏洞。此漏洞由KDesktopFile類處理.desktop或.directory文件的方式引起。如果受害者下載了惡意構(gòu)造的.desktop或.directory文件,惡意文件中注入的bash代碼就會被執(zhí)行。
2019年8月8日,KDE社區(qū)終于在發(fā)布的更新中修復(fù)了該漏洞;在此之前的三天內(nèi),此漏洞是沒有官方補(bǔ)丁的。
PoC有多種形式,此處使用三種方式進(jìn)行復(fù)現(xiàn),第1、2種為驗(yàn)證性復(fù)現(xiàn),第3種為接近真實(shí)情況下攻擊者可能使用的攻擊方式。
1.PoC1:
創(chuàng)建一個(gè)文件名為”payload.desktop”的文件:
在文件中寫入payload:
保存后打開文件管理器,寫入的payload被執(zhí)行:
文件內(nèi)容如下:
2.PoC2:
創(chuàng)建一個(gè)文件名為” .directory”的文件:
使用vi寫入內(nèi)容(此處有坑,KDE的vi輸入backspace鍵會出現(xiàn)奇怪的反應(yīng),很不好用):
寫入payload:
保存后打開文件管理器,payload被成功執(zhí)行:
3.PoC3:
攻擊者在本機(jī)啟動NC監(jiān)聽:
攻擊者將payload文件打包掛載至Web服務(wù)器中,誘導(dǎo)受害者下載:
受害者解壓文件:
解壓后,payload會被執(zhí)行,攻擊者接收到反連的Shell:
詳見: https://wiki.archlinux.org/index.php/Desktop_entries_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
KDE的桌面配置解析參考了XDG的方式,但是包含了KDE自己實(shí)現(xiàn)的功能;并且其實(shí)現(xiàn)與XDG官方定義的功能也有出入,正是此出入導(dǎo)致了漏洞。
在KDE文檔中有如下的話( https://userbase.kde.org/KDE_System_Administration/Configuration_Files#Shell_Expansion ):
Shell ExpansionSo called Shell Expansion can be used to provide more dynamic default values. With shell expansion the value of a configuration key can be constructed from the value of an environment variable.To enable shell expansion for a configuration entry, the key must be followed by [$e]. Normally the expanded form is written into the users configuration file after first use. To prevent that, it is recommend to lock the configuration entry down by using [$ie].Example: Dynamic EntriesThe value for the "Email" entry is determined by filling in the values of the $USER and $HOST environment variables. When joe is logged in on joes_host this will result in a value equal to "joe@joes_host". The setting is not locked down.[Mail Settings]Email[$e]=${USER}@${HOST}
為了提供更加靈活的設(shè)置解析,KDE實(shí)現(xiàn)并支持了動態(tài)配置,而此處的${USER}尤其令人注意,該項(xiàng)取自環(huán)境變量,可以推測,此處與命令執(zhí)行肯定有聯(lián)系。
每當(dāng)KDE桌面系統(tǒng)要讀取圖標(biāo)等桌面配置時(shí),就會調(diào)用一次readEntry函數(shù);從Dominik Penner給出的漏洞細(xì)節(jié)中,可以看到追蹤代碼的過程。整個(gè)漏洞的執(zhí)行過程如下:
首先,創(chuàng)建惡意文件:
payload.desktop[Desktop Entry]Icon[$e]=$(echo hello>~/POC.txt)
進(jìn)入文件管理器,此時(shí)系統(tǒng)會對.desktop文件進(jìn)行解析;進(jìn)入解析Icon的流程,根據(jù)文檔中的說明,參數(shù)中帶有[$e]時(shí)會調(diào)用shell動態(tài)解析命令:
kdesktopfile.cpp:
QString KDesktopFile::readIcon() const{ Q_D(const KDesktopFile); return d->desktopGroup.readEntry("Icon", QString()); }
跟進(jìn),發(fā)現(xiàn)調(diào)用了KConfigPrivate::expandString(aValue):
kconfiggroup.cpp:
QString KConfigGroup::readEntry(const char *key, const QString &aDefault) const{ Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); bool expand = false; // read value from the entry map QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand); if (aValue.isNull()) { aValue = aDefault; } if (expand) { return KConfigPrivate::expandString(aValue); } return aValue;}
再跟進(jìn),結(jié)合之前對KDE官方文檔的解讀,此處是對動態(tài)命令的解析過程,程序會把字符串中第一個(gè)出現(xiàn)的$(與第一個(gè)出現(xiàn)的)之間的部分截取出來,作為命令,然后調(diào)用popen執(zhí)行:
kconfig.cpp
QString KConfigPrivate::expandString(const QString &value){ QString aValue = value; // check for environment variables and make necessary translations int nDollarPos = aValue.indexOf(QLatin1Char('$')); while (nDollarPos != -1 && nDollarPos + 1 < aValue.length()) { // there is at least one $ if (aValue[nDollarPos + 1] == QLatin1Char('(')) { int nEndPos = nDollarPos + 1; // the next character is not $ while ((nEndPos <= aValue.length()) && (aValue[nEndPos] != QLatin1Char(')'))) { nEndPos++; } nEndPos++; QString cmd = aValue.mid(nDollarPos + 2, nEndPos - nDollarPos - 3); QString result;// FIXME: wince does not have pipes#ifndef _WIN32_WCE FILE *fs = popen(QFile::encodeName(cmd).data(), "r"); if (fs) { QTextStream ts(fs, QIODevice::ReadOnly); result = ts.readAll().trimmed(); pclose(fs); }#endif
自此,漏洞利用過程中的代碼執(zhí)行流程分析完畢;可以看到KDE在解析桌面設(shè)置時(shí),以直接使用執(zhí)行系統(tǒng)命令獲取返回值的方式動態(tài)獲得操作系統(tǒng)的一些參數(shù)值;為了獲得諸如${USER}這樣的系統(tǒng)變量直接調(diào)用系統(tǒng)命令,這個(gè)做法是不太妥當(dāng)?shù)摹?
Summary:It is very unclear at this point what a valid use case for this featurewould possibly be. The old documentation only mentions $(hostname) asan example, which can be done with $HOSTNAME instead.
漏洞發(fā)現(xiàn)者在沒有通知官方的情況下直接公布了漏洞細(xì)節(jié),這個(gè)做法比較有爭議。在發(fā)現(xiàn)漏洞時(shí),首先將0day交給誰也是個(gè)問題,個(gè)人認(rèn)為可以將漏洞提交給廠商,待其修復(fù)后再商議是否要公布。可能國際上的hacker思維與國內(nèi)有著比較大的差異,在Dominik Penner的Twitter下竟然有不少的人支持他提前公布0day,他自己也解釋是想要在defcon開始之前提交自己的0day,這個(gè)做法以及眾人的反應(yīng)值得去品味。
[1] 漏洞細(xì)節(jié):
https://gist.github.com/zeropwn/630832df151029cb8f22d5b6b9efaefb
[2] 發(fā)現(xiàn)者推特:
https://twitter.com/zer0pwn/status/1158167374799020039
[3] 演示視頻:
https://www.youtube.com/watch?v=l4z7EOQQs84
[4] 官方修復(fù)細(xì)節(jié):
https://mail.kde.org/pipermail/kde-announce/2019-August/000047.html
[5] 修復(fù)補(bǔ)丁:
https://cgit.kde.org/kconfig.git/commit/?id=5d3e71b1d2ecd2cb2f910036e614ffdfc895aa22
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。