-
漏洞存在于NTFS-3G之中,该程序是由Tuxera公司开发并维护的开源项目,目的是为Linux提供NTFS分区的驱动程序,实现对NTFS文件系统的读写。该程序默认安装在Ubuntu等操作系统中,并且赋予了setuid的权限。NTFS-3G在调用modprobe时没有初始化环境变量,致使存在本地提权的风险。
-
FUSE(用户空间文件系统)作为类UNIX系统平台上可加载的内核模块,允许非特权用户创建功能完备的文件系统,而不需要重新编译内核。FUSE模块仅仅提供kernel模块的接入口,而本身的主要实现代码位于用户空间中,这些接口需要用户自己去实现。
-
在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();
-
代码意思为:利用get_fuse_fstype()检测当前系统是否加载FUSE模块,若未加载,则利用load_fuse_module()中的modprobe,加载FUSE模块。
-
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; }
-
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; }
-
由于NTFS-3G运行在setuid(0)环境中,那么modprobe也运行在root环境中,因此,在一个尚未加载FUSE 的系统中,攻击者可以通过设置环境变量MODPROBE_OPTIONS "-C /tmp/evil_config -d /tmp/evil_root",强制modprobe加载恶意配置文件,导致攻击者具备加载任意代码到系统内核的能力。
-
在现实情况中,FUSE在大部分系统中已被作为内核的一部分,基本都处于已加载的状态。 jannh对这个问题给出了一种解决思路,通过耗尽系统范围内所有进程可以打开的文件句柄的数量 (/proc/sys/fs/file-max),使得NTFS-3G在fopen("/proc/filesystems", "r")时异常,导致get_fuse_fstype()返回
-
补丁中将
load_fuse_module()中的execl(cmd, cmd, "fuse", NULL);
修改成execle(cmd, cmd, "fuse", (char*)NULL, &env);
- cpu需要多核的支持,在qemu启动时加入参数-smp 2,这个是之前一直没有成功的原因