Skip to content

Latest commit

 

History

History

ntfs-3g

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

漏洞分析

  1. 漏洞存在于NTFS-3G之中,该程序是由Tuxera公司开发并维护的开源项目,目的是为Linux提供NTFS分区的驱动程序,实现对NTFS文件系统的读写。该程序默认安装在Ubuntu等操作系统中,并且赋予了setuid的权限。NTFS-3G在调用modprobe时没有初始化环境变量,致使存在本地提权的风险。

  2. FUSE(用户空间文件系统)作为类UNIX系统平台上可加载的内核模块,允许非特权用户创建功能完备的文件系统,而不需要重新编译内核。FUSE模块仅仅提供kernel模块的接入口,而本身的主要实现代码位于用户空间中,这些接口需要用户自己去实现。

  3. 在NTFS-3G驱动模块中,该模块被调用时,即执行src/ntfs-3g.c文件中的main函数,其中一块的代码如下:

        fstype = get_fuse_fstype();
        err = NTFS_VOLUME_NO_PRIVILEGE;
        if (restore_privs())
            goto err_out;
        if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN)
            fstype = load_fuse_module();
    
  4. 代码意思为:利用get_fuse_fstype()检测当前系统是否加载FUSE模块,若未加载,则利用load_fuse_module()中的modprobe,加载FUSE模块。

  5. get_fuse_fstype函数:

    static fuse_fstype get_fuse_fstype(void)                                              
    {
        char buf[256];
        fuse_fstype fstype = FSTYPE_NONE;
        FILE *f = fopen("/proc/filesystems", "r");
        if (!f) {
            ntfs_log_perror("Failed to open /proc/filesystems");
            return FSTYPE_UNKNOWN;
        }
        while (fgets(buf, sizeof(buf), f)) {
            if (strstr(buf, "fuseblk\n")) {
                fstype = FSTYPE_FUSEBLK;
                break;
            }
            if (strstr(buf, "fuse\n"))
                fstype = FSTYPE_FUSE;
        }
        fclose(f);
        return fstype;
    }
    
  6. fopen("/proc/filesystems", "r")函数失败返回FSTYPE_UNKNOWN,此时会导致main函数调用load_fuse_module(),加载fuse模块,load_fuse_module()实现:

    static fuse_fstype load_fuse_module(void)
    {
        int i;
        struct stat st;
        pid_t pid;
        const char *cmd = "/sbin/modprobe";
        char *env = (char*)NULL;
        struct timespec req = { 0, 100000000 };   /* 100 msec */
        fuse_fstype fstype;
        
        if (!stat(cmd, &st) && !geteuid()) {
            pid = fork();
            if (!pid) {
                execl(cmd, cmd, "fuse", NULL);
                _exit(1);
            } else if (pid != -1)
                waitpid(pid, NULL, 0);
        }
        
        for (i = 0; i < 10; i++) {
            /* 
             * We sleep first because despite the detection of the loaded
             * FUSE kernel module, fuse_mount() can still fail if it's not 
             * fully functional/initialized. Note, of course this is still
             * unreliable but usually helps.
             */  
            nanosleep(&req, NULL);
            fstype = get_fuse_fstype();
            if (fstype != FSTYPE_NONE)
                break;
        }
        return fstype;
    }
    
  7. 由于NTFS-3G运行在setuid(0)环境中,那么modprobe也运行在root环境中,因此,在一个尚未加载FUSE 的系统中,攻击者可以通过设置环境变量MODPROBE_OPTIONS "-C /tmp/evil_config -d /tmp/evil_root",强制modprobe加载恶意配置文件,导致攻击者具备加载任意代码到系统内核的能力。

  8. 在现实情况中,FUSE在大部分系统中已被作为内核的一部分,基本都处于已加载的状态。 jannh对这个问题给出了一种解决思路,通过耗尽系统范围内所有进程可以打开的文件句柄的数量 (/proc/sys/fs/file-max),使得NTFS-3G在fopen("/proc/filesystems", "r")时异常,导致get_fuse_fstype()返回

  9. 补丁中将load_fuse_module()中的execl(cmd, cmd, "fuse", NULL);修改成execle(cmd, cmd, "fuse", (char*)NULL, &env);

  10. image

注意事项

  1. cpu需要多核的支持,在qemu启动时加入参数-smp 2,这个是之前一直没有成功的原因

参考

  1. 简书CVE-2017-0358
  2. open-source-ntfs-3g