原文链接: https://paper.seebug.org/1006/
KDE Frameworks是一套由KDE社群所编写的库及软件框架,是KDE Plasma 5及KDE Applications 5的基础,并使用GNU通用公共许可证进行发布。其中所包含的多个独立框架提供了各种常用的功能,包括了硬件集成、文件格式支持、控件、绘图功能、拼写检查等。KDE框架目前被几个Linux发行版所采用,包括了Kubuntu、OpenMandriva、openSUSE和OpenMandriva。
2019年7月28日Dominik Penner(@zer0pwn)发现了KDE framework版本<=5.60.0时存在命令执行漏洞。
2019年8月5日Dominik Penner在Twitter上披露了该漏洞,而此时该漏洞还是0day漏洞。此漏洞由KDesktopFile类处理.desktop或.directory文件的方式引起。如果受害者下载了恶意构造的.desktop或.directory文件,恶意文件中注入的bash代码就会被执行。
2019年8月8日,KDE社区终于在发布的更新中修复了该漏洞;在此之前的三天内,此漏洞是没有官方补丁的。
PoC有多种形式,此处使用三种方式进行复现,第1、2种为验证性复现,第3种为接近真实情况下攻击者可能使用的攻击方式。
1.PoC1:
创建一个文件名为”payload.desktop”的文件:
在文件中写入payload:
保存后打开文件管理器,写入的payload被执行:
文件内容如下:
2.PoC2:
创建一个文件名为” .directory”的文件:
使用vi写入内容(此处有坑,KDE的vi输入backspace键会出现奇怪的反应,很不好用):
写入payload:
保存后打开文件管理器,payload被成功执行:
3.PoC3:
攻击者在本机启动NC监听:
攻击者将payload文件打包挂载至Web服务器中,诱导受害者下载:
受害者解压文件:
解压后,payload会被执行,攻击者接收到反连的Shell:
详见: https://wiki.archlinux.org/index.php/Desktop_entries_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
KDE的桌面配置解析参考了XDG的方式,但是包含了KDE自己实现的功能;并且其实现与XDG官方定义的功能也有出入,正是此出入导致了漏洞。
在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}
为了提供更加灵活的设置解析,KDE实现并支持了动态配置,而此处的${USER}尤其令人注意,该项取自环境变量,可以推测,此处与命令执行肯定有联系。
每当KDE桌面系统要读取图标等桌面配置时,就会调用一次readEntry函数;从Dominik Penner给出的漏洞细节中,可以看到追踪代码的过程。整个漏洞的执行过程如下:
首先,创建恶意文件:
payload.desktop[Desktop Entry]Icon[$e]=$(echo hello>~/POC.txt)
进入文件管理器,此时系统会对.desktop文件进行解析;进入解析Icon的流程,根据文档中的说明,参数中带有[$e]时会调用shell动态解析命令:
kdesktopfile.cpp:
QString KDesktopFile::readIcon() const{ Q_D(const KDesktopFile); return d->desktopGroup.readEntry("Icon", QString()); }
跟进,发现调用了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;}
再跟进,结合之前对KDE官方文档的解读,此处是对动态命令的解析过程,程序会把字符串中第一个出现的$(与第一个出现的)之间的部分截取出来,作为命令,然后调用popen执行:
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
自此,漏洞利用过程中的代码执行流程分析完毕;可以看到KDE在解析桌面设置时,以直接使用执行系统命令获取返回值的方式动态获得操作系统的一些参数值;为了获得诸如${USER}这样的系统变量直接调用系统命令,这个做法是不太妥当的。
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.
漏洞发现者在没有通知官方的情况下直接公布了漏洞细节,这个做法比较有争议。在发现漏洞时,首先将0day交给谁也是个问题,个人认为可以将漏洞提交给厂商,待其修复后再商议是否要公布。可能国际上的hacker思维与国内有着比较大的差异,在Dominik Penner的Twitter下竟然有不少的人支持他提前公布0day,他自己也解释是想要在defcon开始之前提交自己的0day,这个做法以及众人的反应值得去品味。
[1] 漏洞细节:
https://gist.github.com/zeropwn/630832df151029cb8f22d5b6b9efaefb
[2] 发现者推特:
https://twitter.com/zer0pwn/status/1158167374799020039
[3] 演示视频:
https://www.youtube.com/watch?v=l4z7EOQQs84
[4] 官方修复细节:
https://mail.kde.org/pipermail/kde-announce/2019-August/000047.html
[5] 修复补丁:
https://cgit.kde.org/kconfig.git/commit/?id=5d3e71b1d2ecd2cb2f910036e614ffdfc895aa22
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。